Compare commits

..

64 Commits
6.10 ... 6.15

Author SHA1 Message Date
2dust
69050bfe41 up 6.15 2023-03-04 08:52:03 +08:00
2dust
eebc16bcdd Minimize windows when auto-hide is enabled 2023-03-04 08:51:29 +08:00
2dust
d4921535f2 Add lock for db 2023-03-04 08:43:44 +08:00
2dust
b1eeb648a7 Adjust style for icon 2023-03-04 08:36:57 +08:00
2dust
285f91e9e8 bug fixes 2023-03-03 10:45:09 +08:00
2dust
947a7aa7df Modify blacklist rules 2023-03-03 10:15:39 +08:00
2dust
0b37e36036 Merge pull request #3382 from hvvvvvvv/master
解决全局热键不能录制Alt组合键的问题
2023-03-01 09:18:04 +08:00
2dust
92320f5086 Merge pull request #3380 from qiopgh/master
为tun做dns分流
2023-03-01 09:17:52 +08:00
chao wan
ae17e0c264 解决全局热键不能录制Alt组合键的问题 2023-02-28 23:32:58 +08:00
qiopgh
ec756ee943 Update tun_singbox_dns
为tun做dns分流
2023-02-28 22:08:15 +08:00
2dust
b0ff814753 Adjust Running Server ToolTipText 2023-02-28 20:37:45 +08:00
2dust
1f7eb2d48a Optimizing reload core 2023-02-28 20:23:15 +08:00
2dust
eeab8e4a90 Setting tab 2023-02-27 13:26:08 +08:00
2dust
77fbddf488 Improve subscription update without proxy 2023-02-27 13:25:45 +08:00
2dust
bf396f8802 Merge pull request #3370 from hxdhttk/hxdhttk/trayToolTip
Add tray tool tip for the current running server.
2023-02-27 13:04:05 +08:00
Minghao Hu
13cb8b84bf Add tray tool tip for running server. 2023-02-27 11:30:54 +08:00
2dust
3ab992f5fb Merge pull request #3340 from ShiinaRinne/patch-2
Update OptionSettingWindow.xaml
2023-02-24 21:06:27 +08:00
2dust
a386ecfc9c Merge pull request #3336 from ShiinaRinne/patch-1
Update MainWindow.xaml
2023-02-24 21:05:42 +08:00
ShiinaRinne
a71399c42c Update OptionSettingWindow.xaml
调整option页宽度,设置说明自动换行
2023-02-24 15:00:19 +08:00
ShiinaRinne
5a5d7e0981 Update MainWindow.xaml
确保popupbox在点击功能后不会自动关闭,方便测试或多次调整看效果
2023-02-24 12:32:32 +08:00
2dust
b663a7f52a up 6.14 2023-02-24 11:55:32 +08:00
2dust
7390039086 adjust move up and down menu 2023-02-24 11:27:06 +08:00
2dust
12af02435f header sort memory 2023-02-24 11:13:13 +08:00
2dust
6f357828b7 Update SysProxyHandle.cs 2023-02-24 11:11:33 +08:00
2dust
09e1a4386d fix pac bug 2023-02-24 11:11:01 +08:00
2dust
dcc8e6dc34 Add subscription id memory 2023-02-21 20:43:32 +08:00
2dust
1b19ef54e4 Add Tun mode DNS settings 2023-02-21 20:42:55 +08:00
2dust
8ce476caf1 Optimizing sorting storage 2023-02-20 20:15:08 +08:00
2dust
dd2d9133eb Merge pull request #3323 from ilyfairy/master
commit
2023-02-20 19:56:33 +08:00
小仙女
2147d12ac8 update 2023-02-20 18:16:30 +08:00
2dust
22641a1da0 Merge pull request #3315 from ilyfairy/master
修复了一些问题
2023-02-19 20:23:38 +08:00
小仙女
2bd4088d40 使用==替代string.Equals 2023-02-19 19:15:02 +08:00
小仙女
ee61363c31 update 2023-02-19 19:06:35 +08:00
小仙女
8285688ec9 fix: 当过滤器是无效的正则时, 会输出大量异常日志 2023-02-19 18:51:08 +08:00
2dust
4eb076540e Merge pull request #3311 from ilyfairy/master
Update v2rayUpgrade
2023-02-19 16:22:53 +08:00
小仙女
527bfec24c Update v2rayUpgrade 2023-02-19 16:16:10 +08:00
2dust
2fff7d7160 Update TunHandler.cs 2023-02-19 16:09:31 +08:00
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
71 changed files with 2108 additions and 1797 deletions

View File

@@ -20,14 +20,8 @@ public class PacHandler
public static void Start(string configPath, int httpPort, int pacPort) public static void Start(string configPath, int httpPort, int pacPort)
{ {
if (configPath.Equals(_configPath) _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
&& httpPort.Equals(_httpPort)
&& pacPort.Equals(_pacPort)
&& _isRunning)
{
_needRestart = false;
}
_configPath = configPath; _configPath = configPath;
_httpPort = httpPort; _httpPort = httpPort;
_pacPort = pacPort; _pacPort = pacPort;

View File

@@ -139,7 +139,7 @@
x:Key="MyChipListBoxItem" x:Key="MyChipListBoxItem"
BasedOn="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBoxItem}" BasedOn="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBoxItem}"
TargetType="{x:Type ListBoxItem}"> TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="-4,0" /> <Setter Property="Margin" Value="-2,0" />
</Style> </Style>

View File

@@ -6,14 +6,10 @@ namespace v2rayN.Base
{ {
internal class DownloaderHelper internal class DownloaderHelper
{ {
private static readonly Lazy<DownloaderHelper> _instance = new Lazy<DownloaderHelper>(() => new()); private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
public static DownloaderHelper Instance => _instance.Value; public static DownloaderHelper Instance => _instance.Value;
public DownloaderHelper() public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
{
}
public async Task<string> DownloadStringAsync(IWebProxy webProxy, string url, string? userAgent, int timeout)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
{ {
@@ -23,7 +19,7 @@ namespace v2rayN.Base
var cancellationToken = new CancellationTokenSource(); var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000); cancellationToken.CancelAfter(timeout * 1000);
Uri uri = new Uri(url); Uri uri = new(url);
//Authorization Header //Authorization Header
var headers = new WebHeaderCollection(); var headers = new WebHeaderCollection();
if (!Utils.IsNullOrEmpty(uri.UserInfo)) if (!Utils.IsNullOrEmpty(uri.UserInfo))
@@ -44,28 +40,20 @@ namespace v2rayN.Base
} }
}; };
string text = string.Empty; using var downloader = new DownloadService(downloadOpt);
using (var downloader = new DownloadService(downloadOpt)) downloader.DownloadFileCompleted += (sender, value) =>
{ {
downloader.DownloadFileCompleted += (sender, value) => if (value.Error != null)
{ {
if (value.Error != null) throw value.Error;
{
throw new Exception(string.Format("{0}", value.Error.Message));
}
};
using (var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token))
{
using (StreamReader reader = new StreamReader(stream))
{
text = reader.ReadToEnd();
}
} }
} };
using var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
using StreamReader reader = new(stream);
downloadOpt = null; downloadOpt = null;
return text; return reader.ReadToEnd();
} }
@@ -73,7 +61,7 @@ namespace v2rayN.Base
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrEmpty(url))
{ {
throw new ArgumentNullException("url"); throw new ArgumentNullException(nameof(url));
} }
var cancellationToken = new CancellationTokenSource(); var cancellationToken = new CancellationTokenSource();
@@ -94,57 +82,55 @@ namespace v2rayN.Base
int totalSecond = 0; int totalSecond = 0;
var hasValue = false; var hasValue = false;
double maxSpeed = 0; double maxSpeed = 0;
using (var downloader = new DownloadService(downloadOpt)) using var downloader = new DownloadService(downloadOpt);
//downloader.DownloadStarted += (sender, value) =>
//{
// if (progress != null)
// {
// progress.Report("Start download data...");
// }
//};
downloader.DownloadProgressChanged += (sender, value) =>
{ {
//downloader.DownloadStarted += (sender, value) => TimeSpan ts = (DateTime.Now - totalDatetime);
//{ if (progress != null && ts.Seconds > totalSecond)
// if (progress != null)
// {
// progress.Report("Start download data...");
// }
//};
downloader.DownloadProgressChanged += (sender, value) =>
{ {
TimeSpan ts = (DateTime.Now - totalDatetime); hasValue = true;
if (progress != null && ts.Seconds > totalSecond) totalSecond = ts.Seconds;
if (value.BytesPerSecondSpeed > maxSpeed)
{ {
hasValue = true; maxSpeed = value.BytesPerSecondSpeed;
totalSecond = ts.Seconds; var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
if (value.BytesPerSecondSpeed > maxSpeed) progress.Report(speed);
{
maxSpeed = value.BytesPerSecondSpeed;
var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
progress.Report(speed);
}
} }
}; }
downloader.DownloadFileCompleted += (sender, value) => };
downloader.DownloadFileCompleted += (sender, value) =>
{
if (progress != null)
{ {
if (progress != null) if (!hasValue && value.Error != null)
{ {
if (!hasValue && value.Error != null) progress.Report(value.Error?.Message);
{
progress.Report(value.Error?.Message);
}
} }
}; }
progress.Report("......"); };
progress.Report("......");
await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token); using var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
}
downloadOpt = null; downloadOpt = null;
} }
public async Task DownloadFileAsync(IWebProxy webProxy, string url, string fileName, IProgress<double> progress, int timeout) public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
{ {
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))
{ {
@@ -167,38 +153,33 @@ namespace v2rayN.Base
var progressPercentage = 0; var progressPercentage = 0;
var hasValue = false; var hasValue = false;
using (var downloader = new DownloadService(downloadOpt)) using var downloader = new DownloadService(downloadOpt);
downloader.DownloadStarted += (sender, value) =>
{ {
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)
{ {
if (progress != null) progressPercentage = percent;
{ progress.Report(percent);
progress.Report(0); }
} };
}; downloader.DownloadFileCompleted += (sender, value) =>
downloader.DownloadProgressChanged += (sender, value) => {
if (progress != null)
{ {
hasValue = true; if (hasValue && value.Error == null)
var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
if (progressPercentage != percent && percent % 10 == 0)
{ {
progressPercentage = percent; progress.Report(101);
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); await downloader.DownloadFileTaskAsync(url, fileName, cancellationToken: cancellationToken.Token);
}
downloadOpt = null; downloadOpt = null;
} }

View File

@@ -1,6 +1,7 @@
using System.IO; using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Mime;
using System.Text;
namespace v2rayN.Base namespace v2rayN.Base
{ {
@@ -8,208 +9,149 @@ namespace v2rayN.Base
/// </summary> /// </summary>
public class HttpClientHelper public class HttpClientHelper
{ {
private static HttpClientHelper httpClientHelper = null; private readonly static Lazy<HttpClientHelper> _instance = new(() =>
private HttpClient httpClient;
/// <summary>
/// </summary>
private HttpClientHelper() { }
/// <summary>
/// </summary>
/// <returns></returns>
public static HttpClientHelper GetInstance()
{ {
if (httpClientHelper != null) HttpClientHandler handler = new() { UseCookies = false };
{ HttpClientHelper helper = new(new HttpClient(handler));
return httpClientHelper; return helper;
} });
else public static HttpClientHelper Instance => _instance.Value;
{ private readonly HttpClient httpClient;
HttpClientHelper httpClientHelper = new HttpClientHelper();
HttpClientHandler handler = new HttpClientHandler() { UseCookies = false }; private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
httpClientHelper.httpClient = new HttpClient(handler);
return httpClientHelper; public async Task<string?> GetAsync(string url)
} {
if (string.IsNullOrEmpty(url)) return null;
return await httpClient.GetStringAsync(url);
} }
public async Task<string> GetAsync(string url)
{
if (string.IsNullOrEmpty(url))
{
return null;
}
HttpResponseMessage response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync(); public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
}
public async Task<string> GetAsync(HttpClient client, string url, CancellationToken token)
{ {
if (string.IsNullOrEmpty(url)) if (string.IsNullOrWhiteSpace(url)) return null;
{ return await client.GetStringAsync(url, token);
return null;
}
HttpResponseMessage response = await client.GetAsync(url, token);
if (!response.IsSuccessStatusCode)
{
throw new Exception(string.Format("{0}", response.StatusCode));
}
return await response.Content.ReadAsStringAsync();
} }
public async Task PutAsync(string url, Dictionary<string, string> headers) public async Task PutAsync(string url, Dictionary<string, string> headers)
{ {
var myContent = Utils.ToJson(headers); var jsonContent = Utils.ToJson(headers);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent); var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = await httpClient.PutAsync(url, byteContent); var result = await httpClient.PutAsync(url, content);
} }
public async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double> progress, CancellationToken token) public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
{ {
if (string.IsNullOrEmpty(url)) ArgumentNullException.ThrowIfNull(url);
{ ArgumentNullException.ThrowIfNull(fileName);
throw new ArgumentNullException("url"); if (File.Exists(fileName)) File.Delete(fileName);
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("fileName");
}
if (File.Exists(fileName))
{
File.Delete(fileName);
}
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString());
{
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);
var totalRead = 0L;
var buffer = new byte[1024 * 1024];
var progressPercentage = 0;
while (true)
{ {
using (var file = File.Create(fileName)) token.ThrowIfCancellationRequested();
var read = await stream.ReadAsync(buffer, token);
totalRead += read;
if (read == 0) break;
file.Write(buffer, 0, read);
if (canReportProgress)
{ {
var totalRead = 0L; var percent = (int)(100.0 * totalRead / total);
var buffer = new byte[1024 * 1024]; //if (progressPercentage != percent && percent % 10 == 0)
var isMoreToRead = true;
var progressPercentage = 0;
do
{ {
token.ThrowIfCancellationRequested(); progressPercentage = percent;
progress!.Report(percent);
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
if (read == 0)
{
isMoreToRead = false;
}
else
{
var data = new byte[read];
buffer.ToList().CopyTo(0, data, 0, read);
// TODO: put here the code to write the file to disk
file.Write(data, 0, read);
totalRead += read;
if (canReportProgress)
{
var percent = Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
if (progressPercentage != percent && percent % 10 == 0)
{
progressPercentage = percent;
progress.Report(percent);
}
}
}
} while (isMoreToRead);
file.Close();
if (canReportProgress)
{
progress.Report(101);
} }
} }
} }
if (canReportProgress)
{
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 = default)
{ {
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);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
throw new Exception(string.Format("{0}", response.StatusCode)); throw new Exception(response.StatusCode.ToString());
} }
//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 buffer = new byte[1024 * 64];
var isMoreToRead = true;
string progressSpeed = string.Empty;
DateTime totalDatetime = DateTime.Now;
int totalSecond = 0;
do
{ {
var totalRead = 0L; if (token.IsCancellationRequested)
var buffer = new byte[1024 * 64];
var isMoreToRead = true;
string progressSpeed = string.Empty;
DateTime totalDatetime = DateTime.Now;
int totalSecond = 0;
do
{ {
if (token.IsCancellationRequested) if (totalRead > 0)
{ {
if (totalRead > 0) return;
{
return;
}
else
{
token.ThrowIfCancellationRequested();
}
}
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
if (read == 0)
{
isMoreToRead = false;
} }
else else
{ {
var data = new byte[read]; token.ThrowIfCancellationRequested();
buffer.ToList().CopyTo(0, data, 0, read); }
}
// TODO: var read = await stream.ReadAsync(buffer, token);
totalRead += read;
TimeSpan ts = (DateTime.Now - totalDatetime); if (read == 0)
if (progress != null && ts.Seconds > totalSecond) {
isMoreToRead = false;
}
else
{
var data = new byte[read];
buffer.ToList().CopyTo(0, data, 0, read);
// TODO:
totalRead += read;
TimeSpan ts = (DateTime.Now - totalDatetime);
if (progress != null && ts.Seconds > totalSecond)
{
totalSecond = ts.Seconds;
var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0");
if (progressSpeed != speed)
{ {
totalSecond = ts.Seconds; progressSpeed = speed;
var speed = (totalRead * 1d / ts.TotalMilliseconds / 1000).ToString("#0.0"); progress.Report(speed);
if (progressSpeed != speed)
{
progressSpeed = speed;
progress.Report(speed);
}
} }
} }
} while (isMoreToRead); }
} } while (isMoreToRead);
} }
} }

View File

@@ -0,0 +1,10 @@
using System.Windows.Controls;
namespace v2rayN.Base
{
internal class MyDGTextColumn : DataGridTextColumn
{
public string ExName { get; set; }
}
}

View File

@@ -6,11 +6,12 @@ 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; private SQLiteConnection _db;
public SQLiteAsyncConnection _dbAsync; private SQLiteAsyncConnection _dbAsync;
private static readonly object objLock = new();
public SqliteHelper() public SqliteHelper()
{ {
@@ -34,7 +35,10 @@ namespace v2rayN.Base
} }
public int Replace(object model) public int Replace(object model)
{ {
return _db.InsertOrReplace(model); lock (objLock)
{
return _db.InsertOrReplace(model);
}
} }
public async Task<int> Replacesync(object model) public async Task<int> Replacesync(object model)
{ {
@@ -43,7 +47,10 @@ namespace v2rayN.Base
public int Update(object model) public int Update(object model)
{ {
return _db.Update(model); lock (objLock)
{
return _db.Update(model);
}
} }
public async Task<int> UpdateAsync(object model) public async Task<int> UpdateAsync(object model)
{ {
@@ -51,12 +58,18 @@ namespace v2rayN.Base
} }
public int UpdateAll(IEnumerable models) public int UpdateAll(IEnumerable models)
{ {
return _db.UpdateAll(models); lock (objLock)
{
return _db.UpdateAll(models);
}
} }
public int Delete(object model) public int Delete(object model)
{ {
return _db.Delete(model); lock (objLock)
{
return _db.Delete(model);
}
} }
public async Task<int> DeleteAsync(object model) public async Task<int> DeleteAsync(object model)
{ {

View File

@@ -1,15 +1,16 @@
using System.IO; using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace v2rayN.Base namespace v2rayN.Base
{ {
static class StringEx static class StringEx
{ {
public static bool IsNullOrEmpty(this string value) public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{ {
return string.IsNullOrEmpty(value); return string.IsNullOrEmpty(value);
} }
public static bool IsNullOrWhiteSpace(this string value) public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
{ {
return string.IsNullOrWhiteSpace(value); return string.IsNullOrWhiteSpace(value);
} }
@@ -34,7 +35,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;
@@ -42,7 +43,7 @@ namespace v2rayN.Base
} }
} }
public static string TrimEx(this string value) public static string TrimEx(this string? value)
{ {
return value == null ? string.Empty : value.Trim(); return value == null ? string.Empty : value.Trim();
} }

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

@@ -33,6 +33,7 @@
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_"; public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound"; public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound";
public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox"; public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox";
public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
public const string DefaultSecurity = "auto"; public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp"; public const string DefaultNetwork = "tcp";
@@ -80,26 +81,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" },
@@ -107,23 +108,22 @@
{"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", "block", "" }; public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
public static readonly List<string> SpeedTestUrls = new List<string> { @"http://cachefly.cachefly.net/100mb.test", @"http://cachefly.cachefly.net/10mb.test" }; public static readonly List<string> SpeedTestUrls = new() { @"http://cachefly.cachefly.net/100mb.test", @"http://cachefly.cachefly.net/10mb.test" };
#endregion #endregion
#region global variable #region global variable
public static bool reloadCore { get; set; }
public static int statePort { get; set; } public static int statePort { get; set; }
public static Job processJob { get; set; } public static Job processJob { get; set; }
public static bool ShowInTaskbar { get; set; } public static bool ShowInTaskbar { get; set; }

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
@@ -61,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,
@@ -151,9 +151,9 @@ namespace v2rayN.Handler
enableAutoAdjustMainLvColWidth = true enableAutoAdjustMainLvColWidth = true
}; };
} }
if (config.uiItem.mainLvColWidth == null) if (config.uiItem.mainColumnItem == null)
{ {
config.uiItem.mainLvColWidth = new Dictionary<string, int>(); config.uiItem.mainColumnItem = new();
} }
if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage)) if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage))
{ {
@@ -190,22 +190,12 @@ namespace v2rayN.Handler
config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl; config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl;
} }
if (config.guiItem.statisticsFreshRate > 100 || config.guiItem.statisticsFreshRate < 1) if (config.guiItem.statisticsFreshRate is > 100 or < 1)
{ {
config.guiItem.statisticsFreshRate = 1; config.guiItem.statisticsFreshRate = 1;
} }
if (config == null) LazyConfig.Instance.SetConfig(config);
{
Global.reloadCore = false;
}
else
{
Global.reloadCore = true;
}
LazyConfig.Instance.SetConfig(ref config);
return 0; return 0;
} }
/// <summary> /// <summary>
@@ -215,7 +205,6 @@ namespace v2rayN.Handler
/// <returns></returns> /// <returns></returns>
public static int SaveConfig(ref Config config, bool reload = true) public static int SaveConfig(ref Config config, bool reload = true)
{ {
Global.reloadCore = reload;
ToJsonFile(config); ToJsonFile(config);
@@ -438,49 +427,48 @@ 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;
ToJsonFile(config); ToJsonFile(config);
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;
} }
@@ -505,9 +493,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:
@@ -516,7 +505,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;
} }
@@ -526,7 +515,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;
} }
@@ -537,7 +526,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;
} }
@@ -547,18 +536,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;
} }
@@ -695,14 +682,34 @@ 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, string colName, 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();
Enum.TryParse(colName, true, out EServerColName name);
var propertyName = string.Empty; var propertyName = string.Empty;
switch (name) switch (name)
{ {
@@ -713,10 +720,14 @@ namespace v2rayN.Handler
case EServerColName.security: case EServerColName.security:
case EServerColName.network: case EServerColName.network:
case EServerColName.streamSecurity: case EServerColName.streamSecurity:
case EServerColName.delay:
case EServerColName.speed:
propertyName = name.ToString(); propertyName = name.ToString();
break; break;
case EServerColName.delayVal:
propertyName = "delay";
break;
case EServerColName.speedVal:
propertyName = "speed";
break;
case EServerColName.subRemarks: case EServerColName.subRemarks:
propertyName = "subid"; propertyName = "subid";
break; break;
@@ -736,33 +747,31 @@ 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.delayVal)
{ {
var maxSort = lstProfile.Max(t => t.sort) + 10; var maxSort = lstProfile.Max(t => t.sort) + 10;
foreach (var item in lstProfile) foreach (var item in lstProfile)
{ {
if (item.delay <= 0) if (item.delay <= 0)
{ {
item.sort = maxSort; ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
} }
} }
} }
if (name == EServerColName.speed) if (name == EServerColName.speedVal)
{ {
var maxSort = lstProfile.Max(t => t.sort) + 10; var maxSort = lstProfile.Max(t => t.sort) + 10;
foreach (var item in lstProfile) foreach (var item in lstProfile)
{ {
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;
} }
@@ -795,7 +804,7 @@ namespace v2rayN.Handler
List<ProfileItem> source = lstProfile; List<ProfileItem> source = lstProfile;
bool keepOlder = config.guiItem.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)
@@ -830,19 +839,11 @@ 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)
{ {
Global.reloadCore = true;
} }
if (SqliteHelper.Instance.Replace(profileItem) > 0) if (SqliteHelper.Instance.Replace(profileItem) > 0)
@@ -929,11 +930,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)
{ {
@@ -958,7 +959,7 @@ namespace v2rayN.Handler
var existItem = lstOriSub?.FirstOrDefault(t => CompareProfileItem(t, profileItem, true)); var existItem = lstOriSub?.FirstOrDefault(t => CompareProfileItem(t, profileItem, true));
if (existItem != null) if (existItem != null)
{ {
profileItem = existItem; profileItem.indexId = existItem.indexId;
} }
//filter //filter
if (!Utils.IsNullOrEmpty(subFilter)) if (!Utils.IsNullOrEmpty(subFilter))
@@ -971,7 +972,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)
{ {
@@ -1021,14 +1022,21 @@ 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?.inbounds?.Count > 0
&& v2rayConfig.inbounds != null && v2rayConfig.outbounds?.Count > 0)
&& v2rayConfig.inbounds.Count > 0
&& v2rayConfig.outbounds != null
&& v2rayConfig.outbounds.Count > 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);
@@ -1038,9 +1046,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);
@@ -1050,12 +1056,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);
@@ -1065,10 +1066,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);
@@ -1092,7 +1090,7 @@ namespace v2rayN.Handler
{ {
RemoveServerViaSubid(ref config, subid, isSub); RemoveServerViaSubid(ref config, subid, isSub);
} }
if (isSub && lstOriSub != null && lstOriSub.Count == 1) if (isSub && lstOriSub?.Count == 1)
{ {
profileItem.indexId = lstOriSub[0].indexId; profileItem.indexId = lstOriSub[0].indexId;
} }
@@ -1129,16 +1127,16 @@ namespace v2rayN.Handler
//SsSIP008 //SsSIP008
var lstSsServer = Utils.FromJson<List<SsServer>>(clipboardData); var lstSsServer = Utils.FromJson<List<SsServer>>(clipboardData);
if (lstSsServer == null || lstSsServer.Count <= 0) if (lstSsServer?.Count <= 0)
{ {
var ssSIP008 = Utils.FromJson<SsSIP008>(clipboardData); var ssSIP008 = Utils.FromJson<SsSIP008>(clipboardData);
if (ssSIP008?.servers != null && ssSIP008.servers.Count > 0) if (ssSIP008?.servers?.Count > 0)
{ {
lstSsServer = ssSIP008.servers; lstSsServer = ssSIP008.servers;
} }
} }
if (lstSsServer != null && lstSsServer.Count > 0) if (lstSsServer?.Count > 0)
{ {
int counter = 0; int counter = 0;
foreach (var it in lstSsServer) foreach (var it in lstSsServer)
@@ -1168,7 +1166,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);
@@ -1213,7 +1211,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",
@@ -1305,44 +1303,6 @@ namespace v2rayN.Handler
} }
#endregion #endregion
#region UI
public static int AddformMainLvColWidth(ref Config config, string name, int width)
{
if (config.uiItem.mainLvColWidth == null)
{
config.uiItem.mainLvColWidth = new Dictionary<string, int>();
}
if (config.uiItem.mainLvColWidth.ContainsKey(name))
{
config.uiItem.mainLvColWidth[name] = width;
}
else
{
config.uiItem.mainLvColWidth.Add(name, width);
}
ToJsonFile(config);
return 0;
}
public static int GetformMainLvColWidth(ref Config config, string name, int width)
{
if (config.uiItem.mainLvColWidth == null)
{
config.uiItem.mainLvColWidth = new Dictionary<string, int>();
}
if (config.uiItem.mainLvColWidth.ContainsKey(name))
{
return config.uiItem.mainLvColWidth[name];
}
else
{
return width;
}
}
#endregion
#region Routing #region Routing
public static int SaveRoutingItem(ref Config config, RoutingItem item) public static int SaveRoutingItem(ref Config config, RoutingItem item)
@@ -1488,8 +1448,6 @@ namespace v2rayN.Handler
config.routingBasicItem.routingIndexId = routingItem.id; config.routingBasicItem.routingIndexId = routingItem.id;
} }
Global.reloadCore = true;
ToJsonFile(config); ToJsonFile(config);
return 0; return 0;
@@ -1512,7 +1470,7 @@ namespace v2rayN.Handler
var items = LazyConfig.Instance.RoutingItems(); var items = LazyConfig.Instance.RoutingItems();
if (blImportAdvancedRules || items.Count <= 0) if (blImportAdvancedRules || items.Count <= 0)
{ {
var maxSort = items.Max(t => t.sort); var maxSort = items.Count;
//Bypass the mainland //Bypass the mainland
var item2 = new RoutingItem() var item2 = new RoutingItem()
{ {

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;
@@ -90,8 +90,8 @@ namespace v2rayN.Handler
{ {
var dtNow = DateTime.Now; var dtNow = DateTime.Now;
v2rayConfig.log.loglevel = config.coreBasicItem.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
{ {
@@ -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))
@@ -184,8 +184,7 @@ namespace v2rayN.Handler
{ {
try try
{ {
if (v2rayConfig.routing != null if (v2rayConfig.routing?.rules != null)
&& v2rayConfig.routing.rules != null)
{ {
v2rayConfig.routing.domainStrategy = config.routingBasicItem.domainStrategy; v2rayConfig.routing.domainStrategy = config.routingBasicItem.domainStrategy;
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.routingBasicItem.domainMatcher) ? null : config.routingBasicItem.domainMatcher; v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.routingBasicItem.domainMatcher) ? null : config.routingBasicItem.domainMatcher;
@@ -241,25 +240,25 @@ namespace v2rayN.Handler
{ {
rules.port = null; rules.port = null;
} }
if (rules.domain != null && rules.domain.Count == 0) if (rules.domain?.Count == 0)
{ {
rules.domain = null; rules.domain = null;
} }
if (rules.ip != null && rules.ip.Count == 0) if (rules.ip?.Count == 0)
{ {
rules.ip = null; rules.ip = null;
} }
if (rules.protocol != null && rules.protocol.Count == 0) if (rules.protocol?.Count == 0)
{ {
rules.protocol = null; rules.protocol = null;
} }
if (rules.inboundTag != null && rules.inboundTag.Count == 0) if (rules.inboundTag?.Count == 0)
{ {
rules.inboundTag = null; rules.inboundTag = null;
} }
var hasDomainIp = false; var hasDomainIp = false;
if (rules.domain != null && rules.domain.Count > 0) if (rules.domain?.Count > 0)
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
it.ip = null; it.ip = null;
@@ -275,7 +274,7 @@ namespace v2rayN.Handler
v2rayConfig.routing.rules.Add(it); v2rayConfig.routing.rules.Add(it);
hasDomainIp = true; hasDomainIp = true;
} }
if (rules.ip != null && rules.ip.Count > 0) if (rules.ip?.Count > 0)
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
it.domain = null; it.domain = null;
@@ -286,8 +285,8 @@ namespace v2rayN.Handler
if (!hasDomainIp) if (!hasDomainIp)
{ {
if (!Utils.IsNullOrEmpty(rules.port) if (!Utils.IsNullOrEmpty(rules.port)
|| (rules.protocol != null && rules.protocol.Count > 0) || (rules.protocol?.Count > 0)
|| (rules.inboundTag != null && rules.inboundTag.Count > 0) || (rules.inboundTag?.Count > 0)
) )
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
@@ -405,7 +404,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,
@@ -565,7 +564,7 @@ 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.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure), allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(), alpn = node.GetAlpn(),
@@ -587,7 +586,7 @@ 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.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure), allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(), alpn = node.GetAlpn(),
@@ -608,17 +607,17 @@ 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
}; };
if (iobound.Equals("out")) if (iobound == "out")
{ {
kcpSettings.uplinkCapacity = config.kcpItem.uplinkCapacity; kcpSettings.uplinkCapacity = config.kcpItem.uplinkCapacity;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity; kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
} }
else if (iobound.Equals("in")) else if (iobound == "in")
{ {
kcpSettings.uplinkCapacity = config.kcpItem.downlinkCapacity; ; kcpSettings.uplinkCapacity = config.kcpItem.downlinkCapacity; ;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity; kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
@@ -644,12 +643,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 +670,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 +686,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 +709,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),
@@ -728,9 +723,9 @@ namespace v2rayN.Handler
break; break;
default: default:
//tcp //tcp
if (node.headerType.Equals(Global.TcpHeaderHttp)) if (node.headerType == Global.TcpHeaderHttp)
{ {
TcpSettings tcpSettings = new TcpSettings TcpSettings tcpSettings = new()
{ {
header = new Header header = new Header
{ {
@@ -738,7 +733,7 @@ namespace v2rayN.Handler
} }
}; };
if (iobound.Equals("out")) if (iobound == "out")
{ {
//request Host //request Host
string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName); string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName);
@@ -757,7 +752,7 @@ namespace v2rayN.Handler
request = request.Replace("$requestPath$", $"\"{pathHttp}\""); request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
tcpSettings.header.request = Utils.FromJson<object>(request); tcpSettings.header.request = Utils.FromJson<object>(request);
} }
else if (iobound.Equals("in")) else if (iobound == "in")
{ {
//string response = Utils.GetEmbedText(Global.v2raySampleHttpresponseFileName); //string response = Utils.GetEmbedText(Global.v2raySampleHttpresponseFileName);
//tcpSettings.header.response = Utils.FromJson<object>(response); //tcpSettings.header.response = Utils.FromJson<object>(response);
@@ -793,13 +788,13 @@ namespace v2rayN.Handler
} }
var obj = Utils.ParseJson(config.remoteDNS); var obj = Utils.ParseJson(config.remoteDNS);
if (obj != null && obj.ContainsKey("servers")) if (obj?.ContainsKey("servers") == true)
{ {
v2rayConfig.dns = obj; v2rayConfig.dns = obj;
} }
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)
@@ -828,9 +823,9 @@ namespace v2rayN.Handler
if (config.guiItem.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 +842,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 +855,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 +952,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 +1029,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 +1118,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 +1132,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;
@@ -1175,30 +1170,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}"; profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp //tcp or kcp
if (outbound.streamSettings != null if (outbound.streamSettings?.network != null
&& outbound.streamSettings.network != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.network)) && !Utils.IsNullOrEmpty(outbound.streamSettings.network))
{ {
profileItem.network = outbound.streamSettings.network; profileItem.network = outbound.streamSettings.network;
} }
//tcp http //tcp http
if (outbound.streamSettings != null if (outbound.streamSettings?.tcpSettings?.header != null
&& outbound.streamSettings.tcpSettings != null
&& outbound.streamSettings.tcpSettings.header != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.tcpSettings.header.type)) && !Utils.IsNullOrEmpty(outbound.streamSettings.tcpSettings.header.type))
{ {
if (outbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) if (outbound.streamSettings.tcpSettings.header.type == Global.TcpHeaderHttp)
{ {
profileItem.headerType = outbound.streamSettings.tcpSettings.header.type; profileItem.headerType = outbound.streamSettings.tcpSettings.header.type;
string request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request); string? request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request)) if (!Utils.IsNullOrEmpty(request))
{ {
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request); V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null if (v2rayTcpRequest?.headers?.Host?.Count > 0)
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
{ {
profileItem.requestHost = v2rayTcpRequest.headers.Host[0]; profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
} }
@@ -1206,17 +1195,14 @@ namespace v2rayN.Handler
} }
} }
//kcp //kcp
if (outbound.streamSettings != null if (outbound?.streamSettings?.kcpSettings?.header != null
&& outbound.streamSettings.kcpSettings != null
&& outbound.streamSettings.kcpSettings.header != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type)) && !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type))
{ {
profileItem.headerType = outbound.streamSettings.kcpSettings.header.type; profileItem.headerType = outbound.streamSettings.kcpSettings.header.type;
} }
//ws //ws
if (outbound.streamSettings != null if (outbound?.streamSettings?.wsSettings != null)
&& outbound.streamSettings.wsSettings != null)
{ {
if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path)) if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path))
{ {
@@ -1230,24 +1216,20 @@ namespace v2rayN.Handler
} }
//h2 //h2
if (outbound.streamSettings != null if (outbound?.streamSettings?.httpSettings != null)
&& outbound.streamSettings.httpSettings != null)
{ {
if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path)) if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path))
{ {
profileItem.path = outbound.streamSettings.httpSettings.path; profileItem.path = outbound.streamSettings.httpSettings.path;
} }
if (outbound.streamSettings.httpSettings.host != null if (outbound.streamSettings.httpSettings.host?.Count > 0)
&& outbound.streamSettings.httpSettings.host.Count > 0)
{ {
profileItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host); profileItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host);
} }
} }
//tls //tls
if (outbound.streamSettings != null if (outbound?.streamSettings?.security == Global.StreamSecurity)
&& outbound.streamSettings.security != null
&& outbound.streamSettings.security == Global.StreamSecurity)
{ {
profileItem.streamSecurity = Global.StreamSecurity; profileItem.streamSecurity = Global.StreamSecurity;
} }
@@ -1262,21 +1244,21 @@ 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
{ {
string result = Utils.LoadResource(fileName); string? result = Utils.LoadResource(fileName);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
msg = ResUI.FailedReadConfiguration; msg = ResUI.FailedReadConfiguration;
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;
@@ -1313,30 +1295,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}"; profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp //tcp or kcp
if (inbound.streamSettings != null if (inbound.streamSettings?.network != null
&& inbound.streamSettings.network != null
&& !Utils.IsNullOrEmpty(inbound.streamSettings.network)) && !Utils.IsNullOrEmpty(inbound.streamSettings.network))
{ {
profileItem.network = inbound.streamSettings.network; profileItem.network = inbound.streamSettings.network;
} }
//tcp http //tcp http
if (inbound.streamSettings != null if (inbound.streamSettings?.tcpSettings?.header != null
&& inbound.streamSettings.tcpSettings != null
&& inbound.streamSettings.tcpSettings.header != null
&& !Utils.IsNullOrEmpty(inbound.streamSettings.tcpSettings.header.type)) && !Utils.IsNullOrEmpty(inbound.streamSettings.tcpSettings.header.type))
{ {
if (inbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) if (inbound.streamSettings.tcpSettings.header.type == Global.TcpHeaderHttp)
{ {
profileItem.headerType = inbound.streamSettings.tcpSettings.header.type; profileItem.headerType = inbound.streamSettings.tcpSettings.header.type;
string request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request); string? request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request)) if (!Utils.IsNullOrEmpty(request))
{ {
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request); V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null if (v2rayTcpRequest?.headers?.Host?.Count > 0)
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
{ {
profileItem.requestHost = v2rayTcpRequest.headers.Host[0]; profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
} }
@@ -1353,8 +1329,7 @@ namespace v2rayN.Handler
//} //}
//ws //ws
if (inbound.streamSettings != null if (inbound.streamSettings?.wsSettings != null)
&& inbound.streamSettings.wsSettings != null)
{ {
if (!Utils.IsNullOrEmpty(inbound.streamSettings.wsSettings.path)) if (!Utils.IsNullOrEmpty(inbound.streamSettings.wsSettings.path))
{ {
@@ -1368,24 +1343,20 @@ namespace v2rayN.Handler
} }
//h2 //h2
if (inbound.streamSettings != null if (inbound.streamSettings?.httpSettings != null)
&& inbound.streamSettings.httpSettings != null)
{ {
if (!Utils.IsNullOrEmpty(inbound.streamSettings.httpSettings.path)) if (!Utils.IsNullOrEmpty(inbound.streamSettings.httpSettings.path))
{ {
profileItem.path = inbound.streamSettings.httpSettings.path; profileItem.path = inbound.streamSettings.httpSettings.path;
} }
if (inbound.streamSettings.httpSettings.host != null if (inbound.streamSettings.httpSettings.host?.Count > 0)
&& inbound.streamSettings.httpSettings.host.Count > 0)
{ {
profileItem.requestHost = Utils.List2String(inbound.streamSettings.httpSettings.host); profileItem.requestHost = Utils.List2String(inbound.streamSettings.httpSettings.host);
} }
} }
//tls //tls
if (inbound.streamSettings != null if (inbound.streamSettings?.security == Global.StreamSecurity)
&& inbound.streamSettings.security != null
&& inbound.streamSettings.security == Global.StreamSecurity)
{ {
profileItem.streamSecurity = Global.StreamSecurity; profileItem.streamSecurity = Global.StreamSecurity;
} }
@@ -1401,7 +1372,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 +1411,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 +1448,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))
@@ -1490,11 +1461,11 @@ namespace v2rayN.Handler
var port = httpPort; var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++) for (int k = httpPort; k < Global.MaxPort; k++)
{ {
if (lstIpEndPoints != null && lstIpEndPoints.FindIndex(_it => _it.Port == k) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{ {
continue; continue;
} }
if (lstTcpConns != null && lstTcpConns.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0) if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{ {
continue; continue;
} }
@@ -1505,7 +1476,7 @@ namespace v2rayN.Handler
} }
//Port In Used //Port In Used
if (lstIpEndPoints != null && lstIpEndPoints.FindIndex(_it => _it.Port == port) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{ {
continue; continue;
} }
@@ -1513,7 +1484,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 +1494,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 +1511,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,9 +12,9 @@ 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)
@@ -27,46 +27,43 @@ namespace v2rayN.Handler
public void LoadCore(Config config) public void LoadCore(Config config)
{ {
if (Global.reloadCore) var node = ConfigHandler.GetDefaultServer(ref config);
if (node == null)
{ {
var node = ConfigHandler.GetDefaultServer(ref config); ShowMsg(false, ResUI.CheckServerSettings);
if (node == null) return;
{ }
ShowMsg(false, ResUI.CheckServerSettings);
return;
}
if (SetCore(config, node) != 0) if (SetCore(config, node) != 0)
{ {
ShowMsg(false, ResUI.CheckServerSettings); ShowMsg(false, ResUI.CheckServerSettings);
return; return;
} }
string fileName = Utils.GetConfigPath(_coreCConfigRes); string fileName = Utils.GetConfigPath(_coreCConfigRes);
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0) if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
} }
else else
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
ShowMsg(true, $"{node.GetSummary()}"); ShowMsg(true, $"{node.GetSummary()}");
CoreStop(); CoreStop();
CoreStart(node); CoreStart(node);
} }
//start a socks service //start a socks service
if (_process != null && !_process.HasExited && node.configType == EConfigType.Custom && node.preSocksPort > 0) if (_process != null && !_process.HasExited && node.configType == EConfigType.Custom && node.preSocksPort > 0)
{
var itemSocks = new ProfileItem()
{ {
var itemSocks = new ProfileItem() configType = EConfigType.Socks,
{ address = Global.Loopback,
configType = EConfigType.Socks, port = node.preSocksPort
address = Global.Loopback, };
port = node.preSocksPort if (CoreConfigHandler.GenerateClientConfig(itemSocks, null, out string msg2, out string configStr) == 0)
}; {
if (CoreConfigHandler.GenerateClientConfig(itemSocks, null, out string msg2, out string configStr) == 0) _processId = CoreStartViaString(configStr);
{
_processId = CoreStartViaString(configStr);
}
} }
} }
} }
@@ -108,7 +105,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);
@@ -173,7 +170,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
{ {
@@ -181,18 +179,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);
@@ -200,7 +198,7 @@ namespace v2rayN.Handler
}; };
} }
p.Start(); p.Start();
if (node.displayLog) if (displayLog)
{ {
p.BeginOutputReadLine(); p.BeginOutputReadLine();
} }
@@ -208,7 +206,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);
@@ -231,7 +229,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

@@ -14,9 +14,9 @@ namespace v2rayN.Handler
/// </summary> /// </summary>
class DownloadHandle class DownloadHandle
{ {
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
@@ -73,11 +73,7 @@ namespace v2rayN.Handler
var progress = new Progress<double>(); var progress = new Progress<double>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
{ {
if (UpdateCompleted != null) UpdateCompleted?.Invoke(this, new ResultEventArgs(value > 100, $"...{value}%"));
{
string msg = $"...{value}%";
UpdateCompleted(this, new ResultEventArgs(value > 100 ? true : false, msg));
}
}; };
var webProxy = GetWebProxy(blProxy); var webProxy = GetWebProxy(blProxy);
@@ -99,7 +95,7 @@ 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().guiItem.enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webRequestHandler = new SocketsHttpHandler var webRequestHandler = new SocketsHttpHandler
@@ -107,10 +103,10 @@ namespace v2rayN.Handler
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 == HttpStatusCode.Redirect && response.Headers.Location is not null)
{ {
return response.Headers.Location.ToString(); return response.Headers.Location.ToString();
} }
@@ -121,17 +117,131 @@ 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
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = webProxy,
UseProxy = webProxy != null
});
if (Utils.IsNullOrEmpty(userAgent))
{
userAgent = Utils.GetVersion(false);
}
client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent);
Uri uri = new(url);
//Authorization Header
if (!Utils.IsNullOrEmpty(uri.UserInfo))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Utils.Base64Encode(uri.UserInfo));
}
var cts = new CancellationTokenSource();
cts.CancelAfter(1000 * 30);
var result = await HttpClientHelper.Instance.GetAsync(client, url, cts.Token);
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;
}
/// <summary>
/// DownloadString
/// </summary>
/// <param name="url"></param>
public async Task<string?> DownloadStringViaDownloader(string url, bool blProxy, string userAgent)
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy); var webProxy = GetWebProxy(blProxy);
if (Utils.IsNullOrEmpty(userAgent))
{
userAgent = Utils.GetVersion(false);
}
var result = await DownloaderHelper.Instance.DownloadStringAsync(webProxy, url, userAgent, 30); var result = await DownloaderHelper.Instance.DownloadStringAsync(webProxy, url, userAgent, 30);
return result; return result;
} }
@@ -147,52 +257,8 @@ namespace v2rayN.Handler
return null; return null;
} }
/// <summary>
/// DownloadString
/// </summary>
/// <param name="url"></param>
public async Task<string> DownloadStringAsyncOri(string url, bool blProxy, string userAgent)
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = GetWebProxy(blProxy)
});
if (Utils.IsNullOrEmpty(userAgent)) public int RunAvailabilityCheck(IWebProxy? webProxy)
{
userAgent = $"{Utils.GetVersion(false)}";
}
client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent);
Uri uri = new Uri(url);
//Authorization Header
if (!Utils.IsNullOrEmpty(uri.UserInfo))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Utils.Base64Encode(uri.UserInfo));
}
var cts = new CancellationTokenSource();
cts.CancelAfter(1000 * 30);
var result = await HttpClientHelper.GetInstance().GetAsync(client, url, cts.Token);
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
{ {
@@ -222,7 +288,7 @@ namespace v2rayN.Handler
} }
} }
public string GetRealPingTime(string url, WebProxy webProxy, int downloadTimeout, out int responseTime) public string GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout, out int responseTime)
{ {
string msg = string.Empty; string msg = string.Empty;
responseTime = -1; responseTime = -1;
@@ -232,19 +298,14 @@ namespace v2rayN.Handler
myHttpWebRequest.Timeout = downloadTimeout * 1000; myHttpWebRequest.Timeout = downloadTimeout * 1000;
myHttpWebRequest.Proxy = webProxy; myHttpWebRequest.Proxy = webProxy;
Stopwatch timer = new Stopwatch(); Stopwatch timer = Stopwatch.StartNew();
timer.Start();
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); using 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;
} }
timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = timer.Elapsed.Milliseconds;
myHttpWebResponse.Close();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -254,7 +315,7 @@ namespace v2rayN.Handler
return msg; return msg;
} }
private WebProxy GetWebProxy(bool blProxy) private WebProxy? GetWebProxy(bool blProxy)
{ {
if (!blProxy) if (!blProxy)
{ {
@@ -271,25 +332,17 @@ namespace v2rayN.Handler
private bool SocketCheck(string ip, int port) private bool SocketCheck(string ip, int port)
{ {
Socket sock = null;
try try
{ {
IPAddress ipa = IPAddress.Parse(ip); IPEndPoint point = new(IPAddress.Parse(ip), port);
IPEndPoint point = new IPEndPoint(ipa, port); using Socket? sock = new(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;
} }
catch { } catch (Exception)
finally
{ {
if (sock != null) return false;
{
sock.Close();
sock.Dispose();
}
} }
return false;
} }
} }
} }

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)
{ {
@@ -95,18 +108,17 @@ namespace v2rayN.Handler
} }
if (!Utils.IsNullOrEmpty(filter)) if (!Utils.IsNullOrEmpty(filter))
{ {
if (filter.Contains("'")) if (filter.Contains('\''))
{ {
filter = filter.Replace("'", ""); filter = filter.Replace("'", "");
} }
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,28 +127,6 @@ 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).OrderBy(t => t.sort).ToList(); return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
@@ -166,7 +156,7 @@ namespace v2rayN.Handler
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType) public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
{ {
if (profileItem != null && profileItem.coreType != null) if (profileItem?.coreType != null)
{ {
return (ECoreType)profileItem.coreType; return (ECoreType)profileItem.coreType;
} }
@@ -183,16 +173,16 @@ 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)
{ {
InitCoreInfo(); InitCoreInfo();
} }
return coreInfos.Where(t => t.coreType == coreType).FirstOrDefault(); return coreInfos!.FirstOrDefault(t => t.coreType == coreType);
} }
public List<CoreInfo> GetCoreInfos() public List<CoreInfo>? GetCoreInfos()
{ {
if (coreInfos == null) if (coreInfos == null)
{ {
@@ -203,7 +193,7 @@ namespace v2rayN.Handler
private void InitCoreInfo() private void InitCoreInfo()
{ {
coreInfos = new List<CoreInfo>(); coreInfos = new(16);
coreInfos.Add(new CoreInfo coreInfos.Add(new CoreInfo
{ {

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,7 +77,7 @@ 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
{ {
@@ -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;
} }
@@ -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,144 @@
using System.Collections.Concurrent;
using System.Reactive.Linq;
using v2rayN.Base;
using v2rayN.Mode;
namespace v2rayN.Handler
{
class ProfileExHandler
{
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx;
private Queue<string> _queIndexIds = new();
public ConcurrentBag<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 = new(SqliteHelper.Instance.Table<ProfileExItem>());
Task.Run(() =>
{
while (true)
{
var cnt = _queIndexIds.Count;
for (int i = 0; i < cnt; i++)
{
var id = _queIndexIds.Dequeue();
var item = _lstProfileEx.FirstOrDefault(t => t.indexId == id);
if (item is not null)
{
SqliteHelper.Instance.Replace(item);
}
}
Thread.Sleep(1000 * 60);
}
});
}
private void IndexIdEnqueue(string indexId)
{
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
{
_queIndexIds.Enqueue(indexId);
}
}
private void AddProfileEx(string indexId, ref ProfileExItem profileEx)
{
profileEx = new()
{
indexId = indexId,
delay = 0,
speed = 0,
sort = 0
};
_lstProfileEx.Add(profileEx);
IndexIdEnqueue(indexId);
}
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 void 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;
IndexIdEnqueue(indexId);
}
public void 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;
IndexIdEnqueue(indexId);
}
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;
IndexIdEnqueue(indexId);
}
public int GetSort(string indexId)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.indexId == indexId);
if (profileEx == null)
{
return 0;
}
return profileEx.sort;
}
public int GetMaxSort()
{
if (_lstProfileEx.Count <= 0)
{
return 0;
}
return _lstProfileEx.Max(t => t == null ? 0 : t.sort);
}
}
}

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

@@ -55,12 +55,16 @@ namespace v2rayN.Handler
case ESpeedActionType.Tcping: case ESpeedActionType.Tcping:
case ESpeedActionType.Realping: case ESpeedActionType.Realping:
UpdateFunc(it.indexId, ResUI.Speedtesting, ""); UpdateFunc(it.indexId, ResUI.Speedtesting, "");
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
break; break;
case ESpeedActionType.Speedtest: case ESpeedActionType.Speedtest:
UpdateFunc(it.indexId, "", ResUI.Speedtesting); UpdateFunc(it.indexId, "", ResUI.Speedtesting);
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break; break;
case ESpeedActionType.Mixedtest: case ESpeedActionType.Mixedtest:
UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.Speedtesting); UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.Speedtesting);
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break; break;
} }
} }
@@ -117,7 +121,7 @@ namespace v2rayN.Handler
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, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
@@ -129,7 +133,7 @@ namespace v2rayN.Handler
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, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
@@ -150,7 +154,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)
@@ -165,12 +169,11 @@ namespace v2rayN.Handler
{ {
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, ""); 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;
@@ -191,6 +194,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;
@@ -214,7 +218,7 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl; string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout; var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new DownloadHandle(); DownloadHandle downloadHandle = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
@@ -231,19 +235,19 @@ namespace v2rayN.Handler
// UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); // UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
// continue; // continue;
//} //}
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1"); 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); ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
} }
UpdateFunc(it.indexId, "", msg); UpdateFunc(it.indexId, "", msg);
}); });
@@ -254,6 +258,7 @@ namespace v2rayN.Handler
_coreHandler.CoreStopPid(pid); _coreHandler.CoreStopPid(pid);
} }
UpdateFunc("", ResUI.SpeedtestingCompleted); UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
} }
private async Task RunSpeedTestMulti() private async Task RunSpeedTestMulti()
@@ -269,7 +274,7 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl; string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout; var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new DownloadHandle(); DownloadHandle downloadHandle = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
@@ -281,18 +286,18 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1"); 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);
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) => _ = 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); ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
} }
UpdateFunc(it.indexId, "", msg); UpdateFunc(it.indexId, "", msg);
}); });
@@ -306,6 +311,7 @@ namespace v2rayN.Handler
_coreHandler.CoreStopPid(pid); _coreHandler.CoreStopPid(pid);
} }
UpdateFunc("", ResUI.SpeedtestingCompleted); UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
} }
private async Task RunMixedtestAsync() private async Task RunMixedtestAsync()
@@ -317,7 +323,7 @@ namespace v2rayN.Handler
await RunSpeedTestMulti(); await RunSpeedTestMulti();
} }
public string GetRealPingTime(DownloadHandle downloadHandle, WebProxy webProxy) public string GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
{ {
string status = downloadHandle.GetRealPingTime(_config.speedTestItem.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;
@@ -336,11 +342,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)))
@@ -349,7 +355,6 @@ namespace v2rayN.Handler
timer.Stop(); timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = timer.Elapsed.Milliseconds;
clientSocket.Close();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -371,7 +376,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;
@@ -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 });
@@ -162,7 +162,7 @@ namespace v2rayN.Handler
todayDown = 0, todayDown = 0,
dateNow = ticks dateNow = ticks
}; };
_ = SqliteHelper.Instance.Replacesync(_serverStatItem); SqliteHelper.Instance.Replace(_serverStatItem);
_lstServerStat.Add(_serverStatItem); _lstServerStat.Add(_serverStatItem);
} }
} }
@@ -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
{ {
@@ -50,7 +50,7 @@ namespace v2rayN.Handler
{ {
var type = config.sysProxyType; var type = config.sysProxyType;
if (forceDisable && type == ESysProxyType.ForcedChange) if (forceDisable && type != ESysProxyType.Unchanged)
{ {
type = ESysProxyType.ForcedClear; type = ESysProxyType.ForcedClear;
} }
@@ -154,85 +154,82 @@ 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();
// Configure the process using the StartInfo properties.
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
// Need to provide encoding info, or output/error strings we got will be wrong.
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
process.StartInfo.CreateNoWindow = true;
StringBuilder output = new(1024);
StringBuilder error = new(1024);
process.OutputDataReceived += (sender, e) =>
{ {
using (Process process = new Process()) if (e.Data == null)
{ {
// Configure the process using the StartInfo properties. outputWaitHandle.Set();
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
// Need to provide encoding info, or output/error strings we got will be wrong.
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
process.StartInfo.CreateNoWindow = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
try
{
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
}
catch (System.ComponentModel.Win32Exception e)
{
// log the arguments
throw new Exception(process.StartInfo.Arguments);
}
string stderr = error.ToString();
string stdout = output.ToString();
int exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
throw new Exception(stderr);
}
//if (arguments == "query")
//{
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
// {
// throw new Exception("failed to query wininet settings");
// }
// _queryStr = stdout;
//}
} }
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
try
{
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
} }
catch (System.ComponentModel.Win32Exception e)
{
// log the arguments
throw new Exception(process.StartInfo.Arguments);
}
string stderr = error.ToString();
string stdout = output.ToString();
int exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
throw new Exception(stderr);
}
//if (arguments == "query")
//{
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
// {
// throw new Exception("failed to query wininet settings");
// }
// _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;
@@ -44,7 +45,7 @@ namespace v2rayN.Base
{ {
var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks); var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
if (socksPort.Equals(_socksPort) if (socksPort == _socksPort
&& _process != null && _process != null
&& !_process.HasExited) && !_process.HasExited)
{ {
@@ -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$", $"{(!_config.tunModeItem.enabledLog).ToString().ToLower()}");
if (_config.tunModeItem.showWindow) if (_config.tunModeItem.showWindow)
{ {
configStr = configStr.Replace("$log_output$", $""); configStr = configStr.Replace("$log_output$", $"");
@@ -108,16 +111,32 @@ 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(@"\", @"\\")}");
} }
//port //port
configStr = configStr.Replace("$socksPort$", $"{_socksPort}"); configStr = configStr.Replace("$socksPort$", $"{_socksPort}");
//dns
string dnsObject = String.Empty;
if (_config.tunModeItem.bypassMode)
{
dnsObject = _config.tunModeItem.directDNS;
}
else
{
dnsObject = _config.tunModeItem.proxyDNS;
}
if (dnsObject.IsNullOrEmpty() || Utils.ParseJson(dnsObject)?.ContainsKey("servers") == false)
{
dnsObject = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
}
configStr = configStr.Replace("$dns_object$", dnsObject);
//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 +244,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 +255,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 +313,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,51 +35,46 @@ 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.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
{
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
try try
{
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
fileName = Utils.UrlEncode(fileName);
Process process = new()
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); StartInfo = new ProcessStartInfo
fileName = Utils.UrlEncode(fileName);
Process process = new Process
{ {
StartInfo = new ProcessStartInfo FileName = "v2rayUpgrade.exe",
{ Arguments = $"\"{fileName}\"",
FileName = "v2rayUpgrade.exe", WorkingDirectory = Utils.StartupPath()
Arguments = $"\"{fileName}\"",
WorkingDirectory = Utils.StartupPath()
}
};
process.Start();
if (process.Id > 0)
{
_updateFunc(true, "");
} }
} };
catch (Exception ex) process.Start();
if (process.Id > 0)
{ {
_updateFunc(false, ex.Message); _updateFunc(true, "");
} }
} }
else catch (Exception ex)
{ {
_updateFunc(false, args.Msg); _updateFunc(false, ex.Message);
} }
}; }
downloadHandle.Error += (sender2, args) => else
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.Msg);
}; }
} };
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, args.GetException().Message);
};
AbsoluteCompleted += (sender2, args) => AbsoluteCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -106,36 +101,32 @@ 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.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
{ _updateFunc(false, ResUI.MsgUnpacking);
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(false, ResUI.MsgUnpacking);
try try
{
_updateFunc(true, url);
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
}
}
else
{ {
_updateFunc(false, args.Msg); _updateFunc(true, url);
} }
}; catch (Exception ex)
downloadHandle.Error += (sender2, args) => {
_updateFunc(false, ex.Message);
}
}
else
{ {
_updateFunc(true, args.GetException().Message); _updateFunc(false, args.Msg);
}; }
} };
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(true, args.GetException().Message);
};
AbsoluteCompleted += (sender2, args) => AbsoluteCompleted += (sender2, args) =>
{ {
@@ -173,14 +164,14 @@ namespace v2rayN.Handler
Task.Run(async () => Task.Run(async () =>
{ {
//Turn off system proxy //Turn off system proxy
bool bSysProxyType = false; //bool bSysProxyType = false;
if (!blProxy && config.sysProxyType == ESysProxyType.ForcedChange) //if (!blProxy && config.sysProxyType == ESysProxyType.ForcedChange)
{ //{
bSysProxyType = true; // bSysProxyType = true;
config.sysProxyType = ESysProxyType.ForcedClear; // config.sysProxyType = ESysProxyType.ForcedClear;
SysProxyHandle.UpdateSysProxy(config, false); // SysProxyHandle.UpdateSysProxy(config, false);
Thread.Sleep(3000); // Thread.Sleep(3000);
} //}
foreach (var item in subItem) foreach (var item in subItem)
{ {
@@ -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}");
} }
@@ -244,12 +235,12 @@ namespace v2rayN.Handler
} }
_updateFunc(false, "-------------------------------------------------------"); _updateFunc(false, "-------------------------------------------------------");
} }
//restore system proxy ////restore system proxy
if (bSysProxyType) //if (bSysProxyType)
{ //{
config.sysProxyType = ESysProxyType.ForcedChange; // config.sysProxyType = ESysProxyType.ForcedChange;
SysProxyHandle.UpdateSysProxy(config, false); // SysProxyHandle.UpdateSysProxy(config, false);
} //}
_updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}"); _updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
}); });
@@ -262,49 +253,44 @@ 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.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
try
{ {
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName)); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
if (File.Exists(fileName))
try
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); //Global.coreTypes.ForEach(it =>
if (File.Exists(fileName)) //{
{ // string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
//Global.coreTypes.ForEach(it => // File.Copy(fileName, targetPath, true);
//{ //});
// string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it)); string targetPath = Utils.GetBinPath($"{geoName}.dat");
// File.Copy(fileName, targetPath, true); File.Copy(fileName, targetPath, true);
//});
string targetPath = Utils.GetBinPath($"{geoName}.dat");
File.Copy(fileName, targetPath, true);
File.Delete(fileName); File.Delete(fileName);
//_updateFunc(true, ""); //_updateFunc(true, "");
}
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
} }
} }
else catch (Exception ex)
{ {
_updateFunc(false, args.Msg); _updateFunc(false, ex.Message);
} }
}; }
downloadHandle.Error += (sender2, args) => else
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.Msg);
}; }
} };
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, args.GetException().Message);
};
askToDownload(downloadHandle, url, false); askToDownload(downloadHandle, url, false);
} }
@@ -328,7 +314,7 @@ namespace v2rayN.Handler
var coreInfo = LazyConfig.Instance.GetCoreInfo(type); var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
string url = coreInfo.coreReleaseApiUrl; string url = coreInfo.coreReleaseApiUrl;
var result = await (new DownloadHandle()).DownloadStringAsyncOri(url, true, ""); var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
if (!Utils.IsNullOrEmpty(result)) if (!Utils.IsNullOrEmpty(result))
{ {
responseHandler(type, result, preRelease); responseHandler(type, result, preRelease);
@@ -374,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

@@ -9,6 +9,7 @@
#region property #region property
public string indexId { get; set; } public string indexId { get; set; }
public string subIndexId { get; set; }
public string remoteDNS { get; set; } public string remoteDNS { get; set; }
/// <summary> /// <summary>

View File

@@ -123,7 +123,8 @@ namespace v2rayN.Mode
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 string mainMsgFilter { get; set; }
public Dictionary<string, int> mainLvColWidth { get; set; } public List<ColumnItem> mainColumnItem { get; set; }
} }
[Serializable] [Serializable]
@@ -160,6 +161,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; }
@@ -167,8 +169,10 @@ namespace v2rayN.Mode
public bool bypassMode { get; set; } = true; public bool bypassMode { get; set; } = true;
public List<string> directIP { get; set; } public List<string> directIP { get; set; }
public List<string> directProcess { get; set; } public List<string> directProcess { get; set; }
public string directDNS { get; set; }
public List<string> proxyIP { get; set; } public List<string> proxyIP { get; set; }
public List<string> proxyProcess { get; set; } public List<string> proxyProcess { get; set; }
public string proxyDNS { get; set; }
} }
@@ -192,4 +196,12 @@ namespace v2rayN.Mode
public string routingIndexId { get; set; } public string routingIndexId { get; set; }
public bool enableRoutingAdvanced { get; set; } public bool enableRoutingAdvanced { get; set; }
} }
[Serializable]
public class ColumnItem
{
public string Name { get; set; }
public int Width { get; set; }
public int Index { get; set; }
}
} }

View File

@@ -12,8 +12,8 @@ namespace v2rayN.Mode
network, network,
streamSecurity, streamSecurity,
subRemarks, subRemarks,
delay, delayVal,
speed, speedVal,
todayDown, todayDown,
todayUp, todayUp,

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

@@ -816,6 +816,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Move up and down 的本地化字符串。
/// </summary>
public static string menuMoveTo {
get {
return ResourceManager.GetString("menuMoveTo", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Move to group 的本地化字符串。 /// 查找类似 Move to group 的本地化字符串。
/// </summary> /// </summary>
@@ -2564,7 +2573,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Record local logs 的本地化字符串。 /// 查找类似 Enable Log 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLogEnabled { public static string TbSettingsLogEnabled {
get { get {
@@ -2833,6 +2842,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 DNS object, e.g. {&quot;servers&quot;:[]} 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeDNS {
get {
return ResourceManager.GetString("TbSettingsTunModeDNS", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Proxy IP CIDR, separated by commas (,) 的本地化字符串。 /// 查找类似 Proxy IP CIDR, separated by commas (,) 的本地化字符串。
/// </summary> /// </summary>
@@ -3068,7 +3086,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>
@@ -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>
@@ -1126,4 +1126,10 @@
<data name="TbSettingsSpeedTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest Url</value> <value>SpeedTest Url</value>
</data> </data>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS object, e.g. {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</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>
@@ -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>
@@ -1126,4 +1126,10 @@
<data name="TbSettingsSpeedTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>测速文件地址</value> <value>测速文件地址</value>
</data> </data>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS对象例如 {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>移至上下</value>
</data>
</root> </root>

View File

@@ -14,7 +14,14 @@
{ {
"outboundTag": "proxy", "outboundTag": "proxy",
"ip": [ "ip": [
"geoip:telegram" "geoip:cloudflare",
"geoip:cloudfront",
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
], ],
"domain": [ "domain": [
"geosite:gfw", "geosite:gfw",

View File

@@ -1,31 +1,11 @@
{ {
"log": { "log": {
"disabled": false, "disabled": $log_disabled$,
"level": "debug", "level": "debug",
$log_output$ $log_output$
"timestamp": true "timestamp": true
}, },
"dns": { "dns": $dns_object$ ,
"servers": [
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
}
],
"rules": [
{
"geosite": "category-ads-all",
"server": "block",
"disable_cache": true
}
],
"strategy": "ipv4_only"
},
"inbounds": [ "inbounds": [
{ {
"type": "tun", "type": "tun",

View File

@@ -0,0 +1,31 @@
{
"servers": [
{
"tag": "out_dns",
"address": "8.8.8.8",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
}
],
"rules": [
{
"geosite": "cn",
"server": "local",
"disable_cache": true
},
{
"geosite": "category-ads-all",
"server": "block",
"disable_cache": true
}
],
"strategy": "ipv4_only"
}

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,42 +43,38 @@ 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) continue;
}
try
{
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName))
{ {
continue; continue;
} }
try entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
{ }
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName)) catch (IOException ex)
{ {
continue; Utils.SaveLog(ex.Message, ex);
}
entry.ExtractToFile(Path.Combine(toPath, entry.Name), true);
}
catch (IOException 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,11 +48,10 @@ 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)
{ {
@@ -66,22 +65,18 @@ namespace v2rayN
/// 取得存储资源 /// 取得存储资源
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string LoadResource(string res) public static string? LoadResource(string res)
{ {
string result = string.Empty;
try try
{ {
using (StreamReader reader = new StreamReader(res)) if (!File.Exists(res)) return null;
{ return File.ReadAllText(res);
result = reader.ReadToEnd();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); SaveLog(ex.Message, ex);
} }
return result; return null;
} }
/// <summary> /// <summary>
@@ -90,7 +85,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 +93,7 @@ namespace v2rayN
{ {
return default; return default;
} }
T obj = JsonConvert.DeserializeObject<T>(strJson); return JsonConvert.DeserializeObject<T>(strJson);
return obj;
} }
catch catch
{ {
@@ -112,11 +106,15 @@ 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
{ {
if (obj == null)
{
return result;
}
if (indented) if (indented)
{ {
result = JsonConvert.SerializeObject(obj, result = JsonConvert.SerializeObject(obj,
@@ -141,25 +139,23 @@ 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;
if (nullValue)
{ {
JsonSerializer serializer; serializer = new JsonSerializer() { Formatting = Formatting.Indented };
if (nullValue)
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented };
}
else
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
}
serializer.Serialize(file, obj);
} }
else
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
}
serializer.Serialize(file, obj);
result = 0; result = 0;
} }
catch (Exception ex) catch (Exception ex)
@@ -170,12 +166,11 @@ namespace v2rayN
return result; return result;
} }
public static JObject ParseJson(string strJson) public static JObject? ParseJson(string strJson)
{ {
try try
{ {
JObject obj = JObject.Parse(strJson); return JObject.Parse(strJson);
return obj;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -202,11 +197,11 @@ namespace v2rayN
} }
if (wrap) if (wrap)
{ {
return string.Join("," + Environment.NewLine, lst.ToArray()); return string.Join("," + Environment.NewLine, lst);
} }
else else
{ {
return string.Join(",", lst.ToArray()); return string.Join(",", lst);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -225,7 +220,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 +239,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 +333,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 +410,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 +435,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;
@@ -491,7 +486,7 @@ namespace v2rayN
{ {
return true; return true;
} }
if (text.Equals("null")) if (text == "null")
{ {
return true; return true;
} }
@@ -568,18 +563,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;
} }
@@ -642,7 +633,7 @@ namespace v2rayN
string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, ""); string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, "");
string exePath = GetExePath(); string exePath = GetExePath();
if (value?.Equals(exePath) == true || value?.Equals($"\"{exePath}\"") == true) if (value == exePath || value == $"\"{exePath}\"")
{ {
return true; return true;
} }
@@ -682,13 +673,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 +702,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,14 +734,12 @@ 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?.GetValue("Release") != null)
{ {
if (ndpKey != null && ndpKey.GetValue("Release") != null) return (int)ndpKey.GetValue("Release") >= release;
{
return (int)ndpKey.GetValue("Release") >= release ? true : false;
}
return false;
} }
return false;
} }
/// <summary> /// <summary>
@@ -771,31 +760,29 @@ 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));
foreach (var t in tasks)
{ {
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName)); taskService.RootFolder.DeleteTask(t.Name);
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
if (string.IsNullOrEmpty(fileName))
{
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription;
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.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
} }
if (string.IsNullOrEmpty(fileName))
{
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription;
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.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
} }
#endregion #endregion
@@ -904,16 +891,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;
} }
@@ -921,7 +905,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
@@ -1008,7 +992,7 @@ namespace v2rayN
return fileName; return fileName;
} }
public static IPAddress GetDefaultGateway() public static IPAddress? GetDefaultGateway()
{ {
return NetworkInterface return NetworkInterface
.GetAllNetworkInterfaces() .GetAllNetworkInterfaces()
@@ -1071,14 +1055,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, input.CopyTo(sb);
false)) sb.Position = 0;
{ return new StreamReader(sb, Encoding.UTF8).ReadToEnd();
input.CopyTo(sb);
}
return Encoding.UTF8.GetString(sb.ToArray());
} }
public static string GetBackupPath(string filename) public static string GetBackupPath(string filename)
@@ -1177,7 +1158,7 @@ namespace v2rayN
var logger = LogManager.GetLogger("Log2"); var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}"); logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace); logger.Debug(ex.StackTrace);
if (ex != null && ex.InnerException != null) if (ex?.InnerException != null)
{ {
logger.Error(ex.InnerException); logger.Error(ex.InnerException);
} }
@@ -1194,42 +1175,40 @@ 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,
screen.Bounds.Y,
0, 0,
fullImage.Size,
CopyPixelOperation.SourceCopy);
}
int maxTry = 10;
for (int i = 0; i < maxTry; i++)
{
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
Rectangle cropRect = new(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new(screen.Bounds.Width, screen.Bounds.Height);
double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width;
using (Graphics g = Graphics.FromImage(target))
{ {
g.CopyFromScreen(screen.Bounds.X, g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
screen.Bounds.Y, cropRect,
0, 0, GraphicsUnit.Pixel);
fullImage.Size,
CopyPixelOperation.SourceCopy);
} }
int maxTry = 10;
for (int i = 0; i < maxTry; i++) BitmapLuminanceSource source = new(target);
BinaryBitmap bitmap = new(new HybridBinarizer(source));
QRCodeReader reader = new();
Result result = reader.decode(bitmap);
if (result != null)
{ {
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry); string ret = result.Text;
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry); return ret;
Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width;
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
cropRect,
GraphicsUnit.Pixel);
}
BitmapLuminanceSource source = new BitmapLuminanceSource(target);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
Result result = reader.decode(bitmap);
if (result != null)
{
string ret = result.Text;
return ret;
}
} }
} }
} }

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,8 +37,8 @@ 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<string, bool> _dicHeaderSort = new();
private Action<string> _updateView; private Action<string> _updateView;
#endregion #endregion
@@ -175,6 +175,8 @@ namespace v2rayN.ViewModels
[Reactive] [Reactive]
public string RunningServerDisplay { get; set; } public string RunningServerDisplay { get; set; }
[Reactive] [Reactive]
public string RunningServerToolTipText { get; set; }
[Reactive]
public string RunningInfoDisplay { get; set; } public string RunningInfoDisplay { get; set; }
[Reactive] [Reactive]
public string SpeedProxyDisplay { get; set; } public string SpeedProxyDisplay { get; set; }
@@ -218,10 +220,11 @@ namespace v2rayN.ViewModels
{ {
EnableTun = true; EnableTun = true;
} }
_subId = _config.subIndexId;
//RefreshServers();
InitSubscriptionView(); InitSubscriptionView();
RefreshRoutingsMenu(); RefreshRoutingsMenu();
RefreshServers();
var canEditRemove = this.WhenAnyValue( var canEditRemove = this.WhenAnyValue(
x => x.SelectedProfile, x => x.SelectedProfile,
@@ -254,7 +257,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(
@@ -365,7 +368,7 @@ namespace v2rayN.ViewModels
}, canEditRemove); }, canEditRemove);
SortServerResultCmd = ReactiveCommand.Create(() => SortServerResultCmd = ReactiveCommand.Create(() =>
{ {
SortServer((int)EServerColName.delay); SortServer(EServerColName.delayVal.ToString());
}); });
//servers export //servers export
Export2ClientConfigCmd = ReactiveCommand.Create(() => Export2ClientConfigCmd = ReactiveCommand.Create(() =>
@@ -532,13 +535,17 @@ 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)
{ {
var indexIdOld = _config.indexId;
RefreshServers(); RefreshServers();
Reload(); if (indexIdOld != _config.indexId)
{
Reload();
}
if (_config.uiItem.enableAutoAdjustMainLvColWidth) if (_config.uiItem.enableAutoAdjustMainLvColWidth)
{ {
_updateView("AdjustMainLvColWidth"); _updateView("AdjustMainLvColWidth");
@@ -664,6 +671,8 @@ namespace v2rayN.ViewModels
SysProxyHandle.UpdateSysProxy(_config, true); SysProxyHandle.UpdateSysProxy(_config, true);
} }
ProfileExHandler.Instance.SaveTo();
_statistics?.SaveTo(); _statistics?.SaveTo();
_statistics?.Close(); _statistics?.Close();
@@ -689,6 +698,7 @@ namespace v2rayN.ViewModels
return; return;
} }
_subId = SelectedSub?.id; _subId = SelectedSub?.id;
_config.subIndexId = _subId;
RefreshServers(); RefreshServers();
@@ -708,19 +718,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 +743,16 @@ 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, delay = t33 == null ? 0 : t33.delay,
speedVal = t.speed != 0 ? $"{t.speed} {Global.SpeedUnit}" : string.Empty, delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown), 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)(() =>
{ {
@@ -765,7 +777,9 @@ namespace v2rayN.ViewModels
var running = ConfigHandler.GetDefaultServer(ref _config); var running = ConfigHandler.GetDefaultServer(ref _config);
if (running != null) if (running != null)
{ {
RunningServerDisplay = string.Format("{0}:{1}", ResUI.menuServers, running.GetSummary()); var runningSummary = running.GetSummary();
RunningServerDisplay = $"{ResUI.menuServers}:{runningSummary}";
RunningServerToolTipText = runningSummary;
} }
})); }));
} }
@@ -785,7 +799,7 @@ namespace v2rayN.ViewModels
var item = new ComboItem() { ID = it.indexId, Text = name }; var item = new ComboItem() { ID = it.indexId, Text = name };
_servers.Add(item); _servers.Add(item);
if (_config.indexId.Equals(it.indexId)) if (_config.indexId == it.indexId)
{ {
SelectedServer = item; SelectedServer = item;
} }
@@ -801,7 +815,14 @@ namespace v2rayN.ViewModels
{ {
_subItems.Add(item); _subItems.Add(item);
} }
SelectedSub = _subItems[0]; if (_subId != null && _subItems.FirstOrDefault(t => t.id == _subId) != null)
{
SelectedSub = _subItems.FirstOrDefault(t => t.id == _subId);
}
else
{
SelectedSub = _subItems[0];
}
} }
#endregion #endregion
@@ -810,7 +831,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 +855,6 @@ namespace v2rayN.ViewModels
{ {
subid = _subId, subid = _subId,
configType = eConfigType, configType = eConfigType,
displayLog = false
}; };
} }
else else
@@ -876,6 +896,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 +921,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 +996,7 @@ namespace v2rayN.ViewModels
return; return;
} }
if (ConfigHandler.SetDefaultServer(ref _config, item) == 0) if (ConfigHandler.SetDefaultServerIndex(ref _config, indexId) == 0)
{ {
RefreshServers(); RefreshServers();
Reload(); Reload();
@@ -1021,23 +1043,23 @@ namespace v2rayN.ViewModels
await DialogHost.Show(dialog, "RootDialog"); await DialogHost.Show(dialog, "RootDialog");
} }
public void SortServer(int colIndex) public void SortServer(string colName)
{ {
if (colIndex < 0) if (Utils.IsNullOrEmpty(colName))
{ {
return; return;
} }
if (!_dicHeaderSort.ContainsKey(colIndex)) if (!_dicHeaderSort.ContainsKey(colName))
{ {
_dicHeaderSort.Add(colIndex, true); _dicHeaderSort.Add(colName, true);
} }
_dicHeaderSort.TryGetValue(colIndex, out bool asc); _dicHeaderSort.TryGetValue(colName, out bool asc);
if (ConfigHandler.SortServers(ref _config, _subId, (EServerColName)colIndex, asc) != 0) if (ConfigHandler.SortServers(ref _config, _subId, colName, asc) != 0)
{ {
return; return;
} }
_dicHeaderSort[colIndex] = !asc; _dicHeaderSort[colName] = !asc;
RefreshServers(); RefreshServers();
} }
@@ -1158,7 +1180,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 +1205,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 +1279,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|*.*"
@@ -1349,7 +1371,6 @@ namespace v2rayN.ViewModels
public void Reload() public void Reload()
{ {
Global.reloadCore = true;
_ = LoadV2ray(); _ = LoadV2ray();
} }
@@ -1369,7 +1390,6 @@ namespace v2rayN.ViewModels
{ {
_coreHandler.LoadCore(_config); _coreHandler.LoadCore(_config);
Global.reloadCore = false;
//ConfigHandler.SaveConfig(ref _config, false); //ConfigHandler.SaveConfig(ref _config, false);
ChangeSystemProxyStatus(_config.sysProxyType, false); ChangeSystemProxyStatus(_config.sysProxyType, false);
@@ -1445,7 +1465,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.routingBasicItem.routingIndexId)) if (item.id == _config.routingBasicItem.routingIndexId)
{ {
SelectedRouting = item; SelectedRouting = item;
} }
@@ -1521,7 +1541,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;
@@ -1640,7 +1660,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)
@@ -1651,21 +1671,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
@@ -1702,10 +1722,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

@@ -75,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; }
@@ -83,8 +84,10 @@ namespace v2rayN.ViewModels
[Reactive] public bool TunBypassMode2 { get; set; } [Reactive] public bool TunBypassMode2 { get; set; }
[Reactive] public string TunDirectIP { get; set; } [Reactive] public string TunDirectIP { get; set; }
[Reactive] public string TunDirectProcess { get; set; } [Reactive] public string TunDirectProcess { get; set; }
[Reactive] public string TunDirectDNS { get; set; }
[Reactive] public string TunProxyIP { get; set; } [Reactive] public string TunProxyIP { get; set; }
[Reactive] public string TunProxyProcess { get; set; } [Reactive] public string TunProxyProcess { get; set; }
[Reactive] public string TunProxyDNS { get; set; }
#endregion #endregion
#region CoreType #region CoreType
@@ -168,6 +171,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;
@@ -175,8 +179,10 @@ namespace v2rayN.ViewModels
TunBypassMode = _config.tunModeItem.bypassMode; TunBypassMode = _config.tunModeItem.bypassMode;
TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true); TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true);
TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true); TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true);
TunDirectDNS = _config.tunModeItem.directDNS;
TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true); TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true);
TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true); TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true);
TunProxyDNS = _config.tunModeItem.proxyDNS;
this.WhenAnyValue( this.WhenAnyValue(
x => x.TunBypassMode) x => x.TunBypassMode)
.Subscribe(c => TunBypassMode2 = !TunBypassMode); .Subscribe(c => TunBypassMode2 = !TunBypassMode);
@@ -251,7 +257,7 @@ namespace v2rayN.ViewModels
} }
var obj = Utils.ParseJson(remoteDNS); var obj = Utils.ParseJson(remoteDNS);
if (obj != null && obj.ContainsKey("servers")) if (obj?.ContainsKey("servers") == true)
{ {
} }
else else
@@ -275,7 +281,7 @@ namespace v2rayN.ViewModels
//} //}
//Core //Core
_config.inbound[0].localPort = Utils.ToInt(localPort); _config.inbound[0].localPort = localPort;
_config.inbound[0].udpEnabled = udpEnabled; _config.inbound[0].udpEnabled = udpEnabled;
_config.inbound[0].sniffingEnabled = sniffingEnabled; _config.inbound[0].sniffingEnabled = sniffingEnabled;
_config.inbound[0].routeOnly = routeOnly; _config.inbound[0].routeOnly = routeOnly;
@@ -340,6 +346,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;
@@ -347,8 +354,10 @@ namespace v2rayN.ViewModels
_config.tunModeItem.bypassMode = TunBypassMode; _config.tunModeItem.bypassMode = TunBypassMode;
_config.tunModeItem.directIP = Utils.String2List(TunDirectIP); _config.tunModeItem.directIP = Utils.String2List(TunDirectIP);
_config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess); _config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess);
_config.tunModeItem.directDNS = Utils.ToJson(Utils.ParseJson(TunDirectDNS));
_config.tunModeItem.proxyIP = Utils.String2List(TunProxyIP); _config.tunModeItem.proxyIP = Utils.String2List(TunProxyIP);
_config.tunModeItem.proxyProcess = Utils.String2List(TunProxyProcess); _config.tunModeItem.proxyProcess = Utils.String2List(TunProxyProcess);
_config.tunModeItem.proxyDNS = Utils.ToJson(Utils.ParseJson(TunProxyDNS));
//coreType //coreType
SaveCoreType(); SaveCoreType();

View File

@@ -299,7 +299,7 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.OperationSuccess); UI.Show(ResUI.OperationSuccess);
} }
} }
private void ImportRulesFromUrl() private async Task ImportRulesFromUrl()
{ {
var url = SelectedRouting.url; var url = SelectedRouting.url;
if (Utils.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
@@ -308,19 +308,16 @@ namespace v2rayN.ViewModels
return; return;
} }
Task.Run(async () => DownloadHandle downloadHandle = new DownloadHandle();
string result = await downloadHandle.TryDownloadString(url, true, "");
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{ {
DownloadHandle downloadHandle = new DownloadHandle(); Application.Current.Dispatcher.Invoke((Action)(() =>
string result = await downloadHandle.DownloadStringAsync(url, false, "");
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{ {
Application.Current.Dispatcher.Invoke((Action)(() => RefreshRulesItems();
{ }));
RefreshRulesItems(); UI.Show(ResUI.OperationSuccess);
})); }
UI.Show(ResUI.OperationSuccess);
}
});
} }
private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData) private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData)
{ {

View File

@@ -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.routingBasicItem.routingIndexId)) if (item.id == _config.routingBasicItem.routingIndexId)
{ {
def = true; def = true;
} }

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;
@@ -184,12 +185,12 @@ namespace v2rayN.Views
return; return;
} }
if (network.Equals(Global.DefaultNetwork)) if (network == Global.DefaultNetwork)
{ {
cmbHeaderType.Items.Add(Global.None); cmbHeaderType.Items.Add(Global.None);
cmbHeaderType.Items.Add(Global.TcpHeaderHttp); cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
} }
else if (network.Equals("kcp") || network.Equals("quic")) else if (network is "kcp" or "quic")
{ {
cmbHeaderType.Items.Add(Global.None); cmbHeaderType.Items.Add(Global.None);
Global.kcpHeaderTypes.ForEach(it => Global.kcpHeaderTypes.ForEach(it =>
@@ -197,7 +198,7 @@ namespace v2rayN.Views
cmbHeaderType.Items.Add(it); cmbHeaderType.Items.Add(it);
}); });
} }
else if (network.Equals("grpc")) else if (network == "grpc")
{ {
cmbHeaderType.Items.Add(Global.GrpcgunMode); cmbHeaderType.Items.Add(Global.GrpcgunMode);
cmbHeaderType.Items.Add(Global.GrpcmultiMode); cmbHeaderType.Items.Add(Global.GrpcmultiMode);
@@ -221,37 +222,34 @@ namespace v2rayN.Views
tipPath.Text = tipPath.Text =
tipHeaderType.Text = string.Empty; tipHeaderType.Text = string.Empty;
if (network.Equals(Global.DefaultNetwork)) switch (network)
{ {
tipRequestHost.Text = ResUI.TransportRequestHostTip1; case Global.DefaultNetwork:
tipHeaderType.Text = ResUI.TransportHeaderTypeTip1; tipRequestHost.Text = ResUI.TransportRequestHostTip1;
} tipHeaderType.Text = ResUI.TransportHeaderTypeTip1;
else if (network.Equals("kcp")) break;
{ case "kcp":
tipHeaderType.Text = ResUI.TransportHeaderTypeTip2; tipHeaderType.Text = ResUI.TransportHeaderTypeTip2;
tipPath.Text = ResUI.TransportPathTip5; tipPath.Text = ResUI.TransportPathTip5;
} break;
else if (network.Equals("ws")) case "ws":
{ tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipRequestHost.Text = ResUI.TransportRequestHostTip2; tipPath.Text = ResUI.TransportPathTip1;
tipPath.Text = ResUI.TransportPathTip1; break;
} case "h2":
else if (network.Equals("h2")) tipRequestHost.Text = ResUI.TransportRequestHostTip3;
{ tipPath.Text = ResUI.TransportPathTip2;
tipRequestHost.Text = ResUI.TransportRequestHostTip3; break;
tipPath.Text = ResUI.TransportPathTip2; case "quic":
} tipRequestHost.Text = ResUI.TransportRequestHostTip4;
else if (network.Equals("quic")) tipPath.Text = ResUI.TransportPathTip3;
{ tipHeaderType.Text = ResUI.TransportHeaderTypeTip3;
tipRequestHost.Text = ResUI.TransportRequestHostTip4; break;
tipPath.Text = ResUI.TransportPathTip3; case "grpc":
tipHeaderType.Text = ResUI.TransportHeaderTypeTip3; tipPath.Text = ResUI.TransportPathTip4;
} tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
else if (network.Equals("grpc")) labHeaderType.Visibility = Visibility.Hidden;
{ break;
tipPath.Text = ResUI.TransportPathTip4;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
labHeaderType.Visibility = Visibility.Hidden;
} }
} }

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)
@@ -56,19 +57,21 @@ namespace v2rayN.Views
private void TxtGlobalHotkey_KeyDown(object sender, KeyEventArgs e) private void TxtGlobalHotkey_KeyDown(object sender, KeyEventArgs e)
{ {
var txt = ((TextBox)sender); e.Handled = true;
var index = Utils.ToInt(txt.Name.Substring(txt.Name.Length - 1, 1)); var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt };
if (!_ModifierKeys.Contains(e.Key) && !_ModifierKeys.Contains(e.SystemKey))
{
var txt = ((TextBox)sender);
var index = Utils.ToInt(txt.Name.Substring(txt.Name.Length - 1, 1));
var formsKey = (Forms.Keys)KeyInterop.VirtualKeyFromKey(e.Key == Key.System ? e.SystemKey : e.Key);
if (e.Key == Key.System) lstKey[index].KeyCode = formsKey;
return; lstKey[index].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
var formsKey = (Forms.Keys)KeyInterop.VirtualKeyFromKey(e.Key); lstKey[index].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
lstKey[index].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
lstKey[index].KeyCode = formsKey; BindingData(index);
lstKey[index].Alt = Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt); }
lstKey[index].Control = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
lstKey[index].Shift = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
BindingData(index);
} }
private void BindingData(int index) private void BindingData(int index)
@@ -84,19 +87,19 @@ namespace v2rayN.Views
if (item.Control) if (item.Control)
{ {
keys += $"{Forms.Keys.Control.ToString()} + "; keys += $"{Forms.Keys.Control} + ";
} }
if (item.Alt) if (item.Alt)
{ {
keys += $"{Forms.Keys.Alt.ToString()} + "; keys += $"{Forms.Keys.Alt} + ";
} }
if (item.Shift) if (item.Shift)
{ {
keys += $"{Forms.Keys.Shift.ToString()} + "; keys += $"{Forms.Keys.Shift} + ";
} }
if (item.KeyCode != null) if (item.KeyCode != null)
{ {
keys += $"{item.KeyCode.ToString()}"; keys += $"{item.KeyCode}";
} }
SetText($"txtGlobalHotkey{k}", keys); SetText($"txtGlobalHotkey{k}", keys);
@@ -147,11 +150,11 @@ namespace v2rayN.Views
{ {
foreach (UIElement element in gridText.Children) foreach (UIElement element in gridText.Children)
{ {
if (element is TextBox) if (element is TextBox box)
{ {
if (((TextBox)element).Name == name) if (box.Name == name)
{ {
((TextBox)element).Text = txt; box.Text = txt;
} }
} }
} }

View File

@@ -53,7 +53,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Server" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Server" />
<TextBlock Text="{x:Static resx:ResUI.menuServers}" /> <TextBlock Text="{x:Static resx:ResUI.menuServers}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -99,7 +102,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="BookClockOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="BookClockOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuSubscription}" /> <TextBlock Text="{x:Static resx:ResUI.menuSubscription}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -131,7 +137,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="SettingsOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="SettingsOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuSetting}" /> <TextBlock Text="{x:Static resx:ResUI.menuSetting}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -169,7 +178,10 @@
<MenuItem x:Name="menuReload" Padding="8,0"> <MenuItem x:Name="menuReload" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Reload" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Reload" />
<TextBlock Text="{x:Static resx:ResUI.menuReload}" /> <TextBlock Text="{x:Static resx:ResUI.menuReload}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -180,7 +192,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Update" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Update" />
<TextBlock Text="{x:Static resx:ResUI.menuCheckUpdate}" /> <TextBlock Text="{x:Static resx:ResUI.menuCheckUpdate}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -221,7 +236,10 @@
<MenuItem x:Name="menuHelp" Padding="8,0"> <MenuItem x:Name="menuHelp" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="HelpCircleOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="HelpCircleOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuHelp}" /> <TextBlock Text="{x:Static resx:ResUI.menuHelp}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -235,7 +253,10 @@
Click="menuPromotion_Click"> Click="menuPromotion_Click">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="VolumeHigh" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="VolumeHigh" />
<TextBlock Text="{x:Static resx:ResUI.menuPromotion}" /> <TextBlock Text="{x:Static resx:ResUI.menuPromotion}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -249,7 +270,10 @@
Click="menuClose_Click"> Click="menuClose_Click">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Minimize" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Minimize" />
<TextBlock Text="{x:Static resx:ResUI.menuClose}" /> <TextBlock Text="{x:Static resx:ResUI.menuClose}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -259,6 +283,7 @@
<materialDesign:PopupBox <materialDesign:PopupBox
Padding="8,0" Padding="8,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}"> Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
<StackPanel Margin="8"> <StackPanel Margin="8">
<Grid> <Grid>
@@ -333,41 +358,35 @@
</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 <ListBox.ItemTemplate>
x:Name="lstGroup" <DataTemplate>
FontSize="{DynamicResource StdFontSize}" <TextBlock Text="{Binding remarks}" />
ItemContainerStyle="{StaticResource MyChipListBoxItem}" </DataTemplate>
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}"> </ListBox.ItemTemplate>
<ListBox.ItemTemplate> </ListBox>
<DataTemplate> <Button
<TextBlock Text="{Binding remarks}" /> x:Name="btnAddSub"
</DataTemplate> Width="30"
</ListBox.ItemTemplate> Height="30"
</ListBox> Margin="4,0"
<Button Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
x:Name="btnAddSub" <materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
Width="30" </Button>
Height="30" <TextBox
Margin="4,0" x:Name="txtServerFilter"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"> Width="200"
<materialDesign:PackIcon Kind="Plus" /> Margin="4,0"
</Button> VerticalContentAlignment="Center"
<Separator /> materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
<TextBox materialDesign:TextFieldAssist.HasClearButton="True"
x:Name="txtServerFilter" Style="{StaticResource DefTextBox}" />
Width="100" </WrapPanel>
Margin="4,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
materialDesign:TextFieldAssist.HasClearButton="True"
Style="{StaticResource DefTextBox}" />
</ToolBar>
</ToolBarTray>
<materialDesign:ColorZone <materialDesign:ColorZone
Height="50" Height="50"
@@ -465,6 +484,7 @@
CanUserSortColumns="False" CanUserSortColumns="False"
EnableRowVirtualization="True" EnableRowVirtualization="True"
Focusable="True" Focusable="True"
FrozenColumnCount="1"
GridLinesVisibility="All" GridLinesVisibility="All"
HeadersVisibility="All" HeadersVisibility="All"
IsReadOnly="True" IsReadOnly="True"
@@ -545,22 +565,24 @@
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem <MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
x:Name="menuMoveTop" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveTop"
Header="{x:Static resx:ResUI.menuMoveTop}" /> Height="{StaticResource MenuItemHeight}"
<MenuItem Header="{x:Static resx:ResUI.menuMoveTop}" />
x:Name="menuMoveUp" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveUp"
Header="{x:Static resx:ResUI.menuMoveUp}" /> Height="{StaticResource MenuItemHeight}"
<MenuItem Header="{x:Static resx:ResUI.menuMoveUp}" />
x:Name="menuMoveDown" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveDown"
Header="{x:Static resx:ResUI.menuMoveDown}" /> Height="{StaticResource MenuItemHeight}"
<MenuItem Header="{x:Static resx:ResUI.menuMoveDown}" />
x:Name="menuMoveBottom" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveBottom"
Header="{x:Static resx:ResUI.menuMoveBottom}" /> Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}" />
</MenuItem>
<MenuItem <MenuItem
x:Name="menuSelectAll" x:Name="menuSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -607,41 +629,50 @@
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<materialDesign:DataGridTextColumn <base:MyDGTextColumn
Width="80" Width="80"
Binding="{Binding configType}" Binding="{Binding configType}"
ExName="configType"
Header="{x:Static resx:ResUI.LvServiceType}" /> Header="{x:Static resx:ResUI.LvServiceType}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="150" Width="150"
Binding="{Binding remarks}" Binding="{Binding remarks}"
ExName="remarks"
Header="{x:Static resx:ResUI.LvAlias}" /> Header="{x:Static resx:ResUI.LvAlias}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="120" Width="120"
Binding="{Binding address}" Binding="{Binding address}"
ExName="address"
Header="{x:Static resx:ResUI.LvAddress}" /> Header="{x:Static resx:ResUI.LvAddress}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="60" Width="60"
Binding="{Binding port}" Binding="{Binding port}"
ExName="port"
Header="{x:Static resx:ResUI.LvPort}" /> Header="{x:Static resx:ResUI.LvPort}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding security}" Binding="{Binding security}"
ExName="security"
Header="{x:Static resx:ResUI.LvEncryptionMethod}" /> Header="{x:Static resx:ResUI.LvEncryptionMethod}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding network}" Binding="{Binding network}"
ExName="network"
Header="{x:Static resx:ResUI.LvTransportProtocol}" /> Header="{x:Static resx:ResUI.LvTransportProtocol}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding streamSecurity}" Binding="{Binding streamSecurity}"
ExName="streamSecurity"
Header="{x:Static resx:ResUI.LvTLS}" /> Header="{x:Static resx:ResUI.LvTLS}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding subRemarks}" Binding="{Binding subRemarks}"
ExName="subRemarks"
Header="{x:Static resx:ResUI.LvSubscription}" /> Header="{x:Static resx:ResUI.LvSubscription}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding delayVal}" Binding="{Binding delayVal}"
ExName="delayVal"
Header="{x:Static resx:ResUI.LvTestDelay}"> Header="{x:Static resx:ResUI.LvTestDelay}">
<DataGridTextColumn.ElementStyle> <DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"> <Style TargetType="{x:Type TextBlock}">
@@ -649,37 +680,42 @@
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" /> <Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </base:MyDGTextColumn>
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding speedVal}" Binding="{Binding speedVal}"
ExName="speedVal"
Header="{x:Static resx:ResUI.LvTestSpeed}"> Header="{x:Static resx:ResUI.LvTestSpeed}">
<DataGridTextColumn.ElementStyle> <DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"> <Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </base:MyDGTextColumn>
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTodayUp" x:Name="colTodayUp"
Width="100" Width="100"
Binding="{Binding todayUp}" Binding="{Binding todayUp}"
ExName="todayUp"
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" /> Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTodayDown" x:Name="colTodayDown"
Width="100" Width="100"
Binding="{Binding todayDown}" Binding="{Binding todayDown}"
ExName="todayDown"
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" /> Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTotalUp" x:Name="colTotalUp"
Width="100" Width="100"
Binding="{Binding totalUp}" Binding="{Binding totalUp}"
ExName="totalUp"
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" /> Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTotalDown" x:Name="colTotalDown"
Width="100" Width="100"
Binding="{Binding totalDown}" Binding="{Binding totalDown}"
ExName="totalDown"
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" /> Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
</DataGrid.Columns> </DataGrid.Columns>
@@ -701,6 +737,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyClear2" x:Name="menuSystemProxyClear2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" />
</StackPanel> </StackPanel>
@@ -712,6 +749,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxySet2" x:Name="menuSystemProxySet2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" />
</StackPanel> </StackPanel>
@@ -723,6 +761,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyNothing2" x:Name="menuSystemProxyNothing2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" />
</StackPanel> </StackPanel>
@@ -734,6 +773,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyPac2" x:Name="menuSystemProxyPac2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" />
</StackPanel> </StackPanel>

View File

@@ -9,6 +9,7 @@ using System.Windows.Controls.Primitives;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using v2rayN.Base;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx; using v2rayN.Resx;
@@ -157,6 +158,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables);
@@ -189,6 +191,11 @@ namespace v2rayN.Views
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed; spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed;
if (_config.uiItem.autoHideStartup)
{
WindowState = WindowState.Minimized;
}
} }
#region Event #region Event
@@ -197,13 +204,13 @@ namespace v2rayN.Views
{ {
if (action == "AdjustMainLvColWidth") if (action == "AdjustMainLvColWidth")
{ {
Application.Current.Dispatcher.Invoke((Action)(() => Application.Current.Dispatcher.Invoke(() =>
{ {
foreach (var it in lstProfiles.Columns) foreach (var it in lstProfiles.Columns)
{ {
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
} }
})); });
} }
else if (action == "ProfilesFocus") else if (action == "ProfilesFocus")
{ {
@@ -265,14 +272,7 @@ namespace v2rayN.Views
return; return;
} }
//find index if (colHeader.Column.GetType().Name != typeof(MyDGTextColumn).Name)
var index = lstProfiles.Columns.IndexOf(colHeader.Column);
if (index < 0)
{
index = colHeader.TabIndex;
}
if (index == 0)
{ {
foreach (var it in lstProfiles.Columns) foreach (var it in lstProfiles.Columns)
{ {
@@ -282,7 +282,8 @@ namespace v2rayN.Views
return; return;
} }
ViewModel?.SortServer(index); var colName = ((MyDGTextColumn)colHeader.Column).ExName;
ViewModel?.SortServer(colName);
} }
private void menuSelectAll_Click(object sender, RoutedEventArgs e) private void menuSelectAll_Click(object sender, RoutedEventArgs e)
@@ -355,7 +356,7 @@ namespace v2rayN.Views
} }
else else
{ {
if (e.Key == Key.Enter || e.Key == Key.Return) if (e.Key is Key.Enter or Key.Return)
{ {
ViewModel?.SetDefaultServer(); ViewModel?.SetDefaultServer();
} }
@@ -403,7 +404,7 @@ namespace v2rayN.Views
} }
#endregion #endregion
#region UI #region UI
private void RestoreUI() private void RestoreUI()
{ {
@@ -429,11 +430,21 @@ namespace v2rayN.Views
gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star); gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
} }
for (int k = 0; k < lstProfiles.Columns.Count; k++) var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList();
for (int i = 0; i < lvColumnItem.Count; i++)
{ {
var width = ConfigHandler.GetformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].Width.Value)); var item = lvColumnItem[i];
lstProfiles.Columns[k].Width = width; for (int k = 1; k < lstProfiles.Columns.Count; k++)
{
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
if (item2.ExName == item.Name)
{
item2.Width = item.Width;
item2.DisplayIndex = i + 1;
}
}
} }
if (!_config.guiItem.enableStatistics) if (!_config.guiItem.enableStatistics)
{ {
colTodayUp.Visibility = Visibility.Hidden; colTodayUp.Visibility = Visibility.Hidden;
@@ -447,10 +458,19 @@ namespace v2rayN.Views
_config.uiItem.mainWidth = this.Width; _config.uiItem.mainWidth = this.Width;
_config.uiItem.mainHeight = this.Height; _config.uiItem.mainHeight = this.Height;
for (int k = 0; k < lstProfiles.Columns.Count; k++) List<ColumnItem> lvColumnItem = new();
for (int k = 1; k < lstProfiles.Columns.Count; k++)
{ {
ConfigHandler.AddformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].ActualWidth)); var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
lvColumnItem.Add(new()
{
Name = item2.ExName,
Width = Convert.ToInt32(item2.ActualWidth),
Index = item2.DisplayIndex
});
} }
_config.uiItem.mainColumnItem = lvColumnItem;
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1); _config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1);
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1); _config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1);
} }
@@ -471,9 +491,8 @@ namespace v2rayN.Views
} }
private void MenuItem_Click(object sender, RoutedEventArgs e) private void MenuItem_Click(object sender, RoutedEventArgs e)
{ {
if (sender is MenuItem) if (sender is MenuItem item)
{ {
MenuItem item = (MenuItem)sender;
Utils.ProcessStart(item.Tag.ToString()); Utils.ProcessStart(item.Tag.ToString());
} }
} }
@@ -482,7 +501,7 @@ namespace v2rayN.Views
#endregion #endregion
#region Drag and Drop #region Drag and Drop
private Point startPoint = new Point(); private Point startPoint = new();
private int startIndex = -1; private int startIndex = -1;
private string formatData = "ProfileItemModel"; private string formatData = "ProfileItemModel";
@@ -523,8 +542,7 @@ namespace v2rayN.Views
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{ {
// Get the dragged Item // Get the dragged Item
var listView = sender as DataGrid; if (sender is not DataGrid listView) return;
if (listView == null) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource); var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null) return; // Abort if (listViewItem == null) return; // Abort
// Find the data behind the ListViewItem // Find the data behind the ListViewItem
@@ -532,7 +550,7 @@ namespace v2rayN.Views
if (item == null) return; // Abort if (item == null) return; // Abort
// Initialize the drag & drop operation // Initialize the drag & drop operation
startIndex = lstProfiles.SelectedIndex; startIndex = lstProfiles.SelectedIndex;
DataObject dragData = new DataObject(formatData, item); DataObject dragData = new(formatData, item);
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move); DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
} }
} }
@@ -550,8 +568,7 @@ namespace v2rayN.Views
if (e.Data.GetDataPresent(formatData) && sender == e.Source) if (e.Data.GetDataPresent(formatData) && sender == e.Source)
{ {
// Get the drop Item destination // Get the drop Item destination
var listView = sender as DataGrid; if (sender is not DataGrid listView) return;
if (listView == null) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource); var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null) if (listViewItem == null)
{ {
@@ -576,4 +593,4 @@ namespace v2rayN.Views
} }
} }

View File

@@ -11,6 +11,10 @@ namespace v2rayN.Views
public partial class MsgView public partial class MsgView
{ {
private static Config _config; private static Config _config;
private string lastMsgFilter;
private bool lastMsgFilterNotAvailable;
public MsgView() public MsgView()
{ {
InitializeComponent(); InitializeComponent();
@@ -28,28 +32,38 @@ namespace v2rayN.Views
void DelegateAppendText(string msg) void DelegateAppendText(string msg)
{ {
Dispatcher.BeginInvoke(new Action<string>(AppendText), DispatcherPriority.Send, msg); Dispatcher.BeginInvoke(AppendText, DispatcherPriority.Send, msg);
} }
public void AppendText(string msg) public void AppendText(string msg)
{ {
if (msg.Equals(Global.CommandClearMsg)) if (msg == Global.CommandClearMsg)
{ {
ClearMsg(); ClearMsg();
return; return;
} }
if (!togAutoRefresh.IsChecked.Value) if (togAutoRefresh.IsChecked == false)
{ {
return; return;
} }
var MsgFilter = cmbMsgFilter.Text.TrimEx(); var MsgFilter = cmbMsgFilter.Text.TrimEx();
if (!Utils.IsNullOrEmpty(MsgFilter)) if (MsgFilter != lastMsgFilter) lastMsgFilterNotAvailable = false;
if (!string.IsNullOrEmpty(MsgFilter) && !lastMsgFilterNotAvailable)
{ {
if (!Regex.IsMatch(msg, MsgFilter)) try
{ {
return; if (!Regex.IsMatch(msg, MsgFilter)) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD>
{
return;
}
}
catch (Exception)
{
lastMsgFilterNotAvailable = true;
} }
} }
lastMsgFilter = MsgFilter;
ShowMsg(msg); ShowMsg(msg);
} }

View File

@@ -10,12 +10,13 @@
xmlns:resx="clr-namespace:v2rayN.Resx" xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:vms="clr-namespace:v2rayN.ViewModels" xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuSetting}" Title="{x:Static resx:ResUI.menuSetting}"
Width="900" Width="1000"
Height="700" Height="700"
x:TypeArguments="vms:OptionSettingViewModel" x:TypeArguments="vms:OptionSettingViewModel"
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"
@@ -46,7 +47,7 @@
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
</Grid> </Grid>
<TabControl> <TabControl HorizontalContentAlignment="Left">
<TabItem Header="{x:Static resx:ResUI.TbSettingsCore}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCore}">
<ScrollViewer VerticalScrollBarVisibility="Visible"> <ScrollViewer VerticalScrollBarVisibility="Visible">
<Grid Margin="{StaticResource SettingItemMargin}"> <Grid Margin="{StaticResource SettingItemMargin}">
@@ -484,7 +485,7 @@
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
@@ -506,7 +507,8 @@
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}" /> Text="{x:Static resx:ResUI.TbSettingsStartBootTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -718,7 +720,8 @@
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}" /> Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="16" Grid.Row="16"
@@ -815,7 +818,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"
@@ -823,6 +826,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}"
@@ -926,13 +943,15 @@
<Grid <Grid
x:Name="gridTunModeDirect" x:Name="gridTunModeDirect"
Width="600" Width="800"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"> HorizontalAlignment="Left">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="10" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
@@ -957,17 +976,31 @@
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="4"
Header="{x:Static resx:ResUI.TbSettingsTunModeDNS}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtDirectDNS"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid> </Grid>
<Grid <Grid
x:Name="gridTunModeProxy" x:Name="gridTunModeProxy"
Width="600" Width="800"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"> HorizontalAlignment="Left">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="10" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
@@ -992,6 +1025,18 @@
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="4"
Header="{x:Static resx:ResUI.TbSettingsTunModeDNS}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyDNS"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid> </Grid>
</DockPanel> </DockPanel>

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);
@@ -75,13 +76,12 @@ namespace v2rayN.Views
//fill fonts //fill fonts
try try
{ {
var dir = new DirectoryInfo(Utils.GetFontsPath()); var files = Directory.GetFiles(Utils.GetFontsPath(), "*.ttf");
var files = dir.GetFiles("*.ttf"); var culture = _config.uiItem.currentLanguage == Global.Languages[0] ? "zh-cn" : "en-us";
var culture = _config.uiItem.currentLanguage.Equals(Global.Languages[0]) ? "zh-cn" : "en-us";
var culture2 = "en-us"; var culture2 = "en-us";
foreach (var it in files) foreach (var ttf in files)
{ {
var families = Fonts.GetFontFamilies(Utils.GetFontsPath(it.Name)); var families = Fonts.GetFontFamilies(Utils.GetFontsPath(ttf));
foreach (FontFamily family in families) foreach (FontFamily family in families)
{ {
var typefaces = family.GetTypefaces(); var typefaces = family.GetTypefaces();
@@ -171,6 +171,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);
@@ -180,8 +181,10 @@ namespace v2rayN.Views
this.OneWayBind(ViewModel, vm => vm.TunBypassMode2, v => v.gridTunModeProxy.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.TunBypassMode2, v => v.gridTunModeProxy.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunDirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectDNS, v => v.txtDirectDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyIP, v => v.txtProxyIP.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunProxyIP, v => v.txtProxyIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyProcess, v => v.txtProxyProcess.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunProxyProcess, v => v.txtProxyProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyDNS, v => v.txtProxyDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.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"
@@ -31,28 +32,40 @@
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignToolBar}">
<Button x:Name="menuRuleAdd"> <Button x:Name="menuRuleAdd">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Plus" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Plus" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRuleAdd}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuRuleAdd}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuImportRulesFromFile"> <Button x:Name="menuImportRulesFromFile">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Import" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Import" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromFile}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromFile}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuImportRulesFromClipboard"> <Button x:Name="menuImportRulesFromClipboard">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Import" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Import" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromClipboard}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromClipboard}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuImportRulesFromUrl"> <Button x:Name="menuImportRulesFromUrl">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Import" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Import" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromUrl}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuImportRulesFromUrl}" />
</StackPanel> </StackPanel>
</Button> </Button>

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;

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"
@@ -38,7 +39,10 @@
<MenuItem x:Name="menuRoutingBasic" Padding="8,0"> <MenuItem x:Name="menuRoutingBasic" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Server" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Server" />
<TextBlock Text="{x:Static resx:ResUI.menuRoutingBasic}" /> <TextBlock Text="{x:Static resx:ResUI.menuRoutingBasic}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -53,7 +57,10 @@
<MenuItem x:Name="menuRoutingAdvanced" Padding="8,0"> <MenuItem x:Name="menuRoutingAdvanced" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Routes" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Routes" />
<TextBlock Text="{x:Static resx:ResUI.menuRoutingAdvanced}" /> <TextBlock Text="{x:Static resx:ResUI.menuRoutingAdvanced}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>

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"
@@ -32,28 +33,40 @@
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignToolBar}">
<Button x:Name="menuSubAdd"> <Button x:Name="menuSubAdd">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Plus" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Plus" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubAdd}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubAdd}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuSubDelete"> <Button x:Name="menuSubDelete">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Delete" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Delete" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubDelete}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubDelete}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuSubEdit"> <Button x:Name="menuSubEdit">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Edit" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Edit" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubEdit}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubEdit}" />
</StackPanel> </StackPanel>
</Button> </Button>
<Separator /> <Separator />
<Button x:Name="menuSubShare"> <Button x:Name="menuSubShare">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="QrcodePlus" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="QrcodePlus" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubShare}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuSubShare}" />
</StackPanel> </StackPanel>
</Button> </Button>
@@ -62,7 +75,10 @@
Click="menuClose_Click" Click="menuClose_Click"
IsCancel="True"> IsCancel="True">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Close" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Close" />
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuClose}" /> <TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.menuClose}" />
</StackPanel> </StackPanel>
</Button> </Button>

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,10 @@
<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.10</FileVersion> <FileVersion>6.15</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Downloader" Version="3.0.3" /> <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" />
@@ -35,6 +36,9 @@
<EmbeddedResource Include="Sample\tun_singbox"> <EmbeddedResource Include="Sample\tun_singbox">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Sample\tun_singbox_dns">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Sample\custom_routing_black"> <EmbeddedResource Include="Sample\custom_routing_black">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>
@@ -64,7 +68,7 @@
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Sample\SampleServerConfig"> <EmbeddedResource Include="Sample\SampleServerConfig">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="v2rayN.ico"> <EmbeddedResource Include="v2rayN.ico">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource> </EmbeddedResource>

View File

@@ -11,18 +11,22 @@ namespace v2rayUpgrade
public partial class MainForm : Form public partial class MainForm : Form
{ {
private readonly string defaultFilename = "v2ray-windows.zip"; private readonly string defaultFilename = "v2ray-windows.zip";
private string fileName; private string? fileName;
public MainForm(string[] args) public MainForm(string[] args)
{ {
InitializeComponent(); InitializeComponent();
if (args.Length > 0) if (args.Length > 0)
{ {
fileName = string.Join(" ", args); fileName = HttpUtility.UrlDecode(string.Join(" ", args));
fileName = HttpUtility.UrlDecode(fileName); }
else
{
fileName = defaultFilename;
} }
} }
private void showWarn(string message)
private void ShowWarn(string message)
{ {
MessageBox.Show(message, "", MessageBoxButtons.OK, MessageBoxIcon.Warning); MessageBox.Show(message, "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
} }
@@ -34,7 +38,7 @@ namespace v2rayUpgrade
Process[] existing = Process.GetProcessesByName("v2rayN"); Process[] existing = Process.GetProcessesByName("v2rayN");
foreach (Process p in existing) foreach (Process p in existing)
{ {
string path = p.MainModule.FileName; string? path = p.MainModule?.FileName;
if (path == GetPath("v2rayN.exe")) if (path == GetPath("v2rayN.exe"))
{ {
p.Kill(); p.Kill();
@@ -45,72 +49,67 @@ namespace v2rayUpgrade
catch (Exception ex) catch (Exception ex)
{ {
// Access may be denied without admin right. The user may not be an administrator. // Access may be denied without admin right. The user may not be an administrator.
showWarn("Failed to close v2rayN(关闭v2rayN失败).\n" + ShowWarn("Failed to close v2rayN(关闭v2rayN失败).\n" +
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace); "Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace);
} }
StringBuilder sb = new StringBuilder(); if (!File.Exists(fileName))
{
if (File.Exists(defaultFilename))
{
fileName = defaultFilename;
}
else
{
ShowWarn("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
return;
}
}
StringBuilder sb = new();
try try
{ {
if (!File.Exists(fileName)) string thisAppOldFile = $"{Application.ExecutablePath}.tmp";
{
if (File.Exists(defaultFilename))
{
fileName = defaultFilename;
}
else
{
showWarn("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
return;
}
}
string thisAppOldFile = Application.ExecutablePath + ".tmp";
File.Delete(thisAppOldFile); File.Delete(thisAppOldFile);
string startKey = "v2rayN/"; string startKey = "v2rayN/";
using ZipArchive archive = ZipFile.OpenRead(fileName);
using (ZipArchive archive = ZipFile.OpenRead(fileName)) foreach (ZipArchiveEntry entry in archive.Entries)
{ {
foreach (ZipArchiveEntry entry in archive.Entries) try
{ {
try if (entry.Length == 0)
{ {
if (entry.Length == 0) continue;
{
continue;
}
string fullName = entry.FullName;
if (fullName.StartsWith(startKey))
{
fullName = fullName.Substring(startKey.Length, fullName.Length - startKey.Length);
}
if (Application.ExecutablePath.ToLower() == GetPath(fullName).ToLower())
{
File.Move(Application.ExecutablePath, thisAppOldFile);
}
string entryOuputPath = GetPath(fullName);
FileInfo fileInfo = new FileInfo(entryOuputPath);
fileInfo.Directory.Create();
entry.ExtractToFile(entryOuputPath, true);
} }
catch (Exception ex) string fullName = entry.FullName;
if (fullName.StartsWith(startKey))
{ {
sb.Append(ex.StackTrace); fullName = fullName[startKey.Length..];
} }
if (string.Equals(Application.ExecutablePath, GetPath(fullName), StringComparison.OrdinalIgnoreCase))
{
File.Move(Application.ExecutablePath, thisAppOldFile);
}
string entryOuputPath = GetPath(fullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryOuputPath)!);
entry.ExtractToFile(entryOuputPath, true);
}
catch (Exception ex)
{
sb.Append(ex.StackTrace);
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
showWarn("Upgrade Failed(升级失败)." + ex.StackTrace); ShowWarn("Upgrade Failed(升级失败)." + ex.StackTrace);
return; return;
} }
if (sb.Length > 0) if (sb.Length > 0)
{ {
showWarn("Upgrade Failed,Hold ctrl + c to copy to clipboard.\n" + ShowWarn("Upgrade Failed,Hold ctrl + c to copy to clipboard.\n" +
"(升级失败,按住ctrl+c可以复制到剪贴板)." + sb.ToString()); "(升级失败,按住ctrl+c可以复制到剪贴板)." + sb.ToString());
return; return;
} }

View File

@@ -6,5 +6,6 @@
<Copyright>Copyright © 2019-2023 (GPLv3)</Copyright> <Copyright>Copyright © 2019-2023 (GPLv3)</Copyright>
<FileVersion>1.1.0.0</FileVersion> <FileVersion>1.1.0.0</FileVersion>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
</Project> </Project>