Compare commits

...

151 Commits
6.10 ... 6.22

Author SHA1 Message Date
2dust
34b4b9d099 up 6.22 2023-04-13 16:00:30 +08:00
2dust
0808ec1612 Add Check update for sing-box core 2023-04-13 15:50:28 +08:00
2dust
6b12549cd9 bug fixes 2023-04-12 20:15:17 +08:00
2dust
92baf9025a Update StatisticsHandler.cs 2023-04-12 15:30:07 +08:00
2dust
d58861ab88 Adjust some style 2023-04-12 14:26:37 +08:00
2dust
142230e56a Fix description 2023-04-12 14:08:30 +08:00
2dust
b8959c8f12 Optimize server filter 2023-04-12 11:34:42 +08:00
2dust
3fa22fdc55 bug fixes 2023-04-11 20:18:49 +08:00
2dust
a1c743e59c bug fixes 2023-04-10 17:30:27 +08:00
2dust
ebd0f45c10 Adjust VLESS flow config 2023-04-10 16:21:19 +08:00
2dust
fce6c46250 Can set the update interval for each subscription 2023-04-10 16:00:32 +08:00
2dust
6114e4ff55 Temporary fix for arm64 grpc issues 2023-04-10 11:28:53 +08:00
2dust
cc3d1ff7de Update Package Reference 2023-04-09 09:13:28 +08:00
2dust
2f721c8535 Merge pull request #3635 from kidfruit/core-arm
Core arm
2023-04-09 08:26:33 +08:00
kidfruit
ddb790104f delete .vs 2023-04-08 12:57:11 +08:00
liqi
181dfd2f51 add arm64 download path for core 2023-04-07 21:32:28 +08:00
liqi
fca062f75a add arm64 download path for core 2023-04-07 18:13:37 +08:00
2dust
52b84c3201 bug fixes 2023-04-07 15:38:30 +08:00
2dust
e1021a6832 Merge pull request #3631 from fonaix/master
fix bug #3630
2023-04-07 15:37:28 +08:00
fonaix
aa338d2da5 fix bug #3630 2023-04-07 15:21:09 +08:00
2dust
44471c4926 Update README.md 2023-04-07 13:56:16 +08:00
2dust
930c7e4ce5 Update README.md 2023-04-07 13:55:32 +08:00
2dust
2e64f23ef9 up 6.21 2023-04-07 11:03:23 +08:00
2dust
801d1fd320 clean up res 2023-04-07 10:16:05 +08:00
2dust
cfffb5756e Update ResUI.zh-Hans.resx 2023-04-06 20:39:40 +08:00
2dust
b30daf8e56 Add more subscription url for one group 2023-04-06 15:09:49 +08:00
2dust
84eba671f0 Optimize add batch servers 2023-04-06 11:40:28 +08:00
2dust
f28b93daa0 Use H.NotifyIcon.Wpf 2023-04-06 10:44:58 +08:00
2dust
dc16136c59 Add Reboot as administrator 2023-04-06 10:44:29 +08:00
2dust
e47caf8c4f VLESS flow check 2023-04-05 21:07:47 +08:00
2dust
8ad80bb75d Remove System.Windows.Forms references 2023-04-05 20:53:05 +08:00
2dust
22475e459d Remove the function of minimizing at startup, because it affects the startup position 2023-04-05 09:43:33 +08:00
2dust
73ad33dfc9 Merge pull request #3611 from fonaix/master
fix bug #3218  and optimize the background color display effect of the active row
2023-04-05 08:23:33 +08:00
fonaix
f1782c78f4 fix bug #3218 2023-04-05 00:57:30 +08:00
fonaix
b544dde2c6 Optimize the background color display effect of the active row 2023-04-04 23:39:56 +08:00
2dust
1a7dca8e58 Fix subscription update duplicate server bug 2023-04-04 20:19:52 +08:00
2dust
23c7d7fb46 Remove some System.Windows.Forms references 2023-04-04 15:59:28 +08:00
2dust
65fda407dc RemoveSystem.Windows.Forms references 2023-04-04 15:59:08 +08:00
2dust
12ebad436a Autofit Column Width 2023-04-04 13:30:29 +08:00
2dust
c7297dba7e Merge pull request #3598 from JasonWues/master
当前选中节点标识改为背景颜色更改
2023-04-04 10:31:56 +08:00
2dust
e61368a26e Remove some System.Windows.Forms references 2023-04-04 10:22:13 +08:00
2dust
b98da3a5dc Optimized move to group 2023-04-04 10:21:12 +08:00
2dust
12f3400894 Subscription multi-select delete 2023-04-04 10:20:19 +08:00
Metatron
4b5508fc3c Style change 2023-04-03 14:43:30 +08:00
Metatron
5f40e6e0b7 fix 2023-04-03 10:50:56 +08:00
Metatron
080d660cfa Select row background change 2023-04-03 10:45:21 +08:00
2dust
790209efbc up 6.20 2023-04-01 18:57:24 +08:00
2dust
f1679e444c Add skip subscription tips 2023-03-31 20:07:39 +08:00
2dust
9dc6ba182a Fix delete duplicate server 2023-03-30 14:09:14 +08:00
2dust
785a30e623 Update CoreConfigHandler.cs 2023-03-26 20:05:51 +08:00
2dust
f09efdad66 Add tip for custom log 2023-03-25 18:05:01 +08:00
2dust
4e73b3ae28 Adjust some style 2023-03-25 17:50:32 +08:00
2dust
6213f86f81 up 6.19 2023-03-21 17:20:24 +08:00
2dust
0a6955cd59 Add log start core 2023-03-21 14:22:13 +08:00
2dust
6ee8f03ec0 Gui's log can be turned off 2023-03-20 15:25:58 +08:00
2dust
b1a82d95c2 Hide title when title width is equal to 0 2023-03-20 15:23:29 +08:00
2dust
30bc9ded29 Add REALITY share link 2023-03-20 15:20:55 +08:00
2dust
5a32892e94 bug fixes 2023-03-20 14:03:50 +08:00
2dust
e33de896b6 Merge pull request #3507 from ShiinaRinne/dev
Update: 默认关闭硬件加速
2023-03-20 13:23:58 +08:00
ShiinaRinne
3ba92444a5 Update: 默认关闭硬件加速
开启硬件加速时可能会导致奇奇怪怪的问题,因此修改为默认关闭
https://github.com/2dust/v2rayN/issues/3379
https://github.com/2dust/v2rayN/issues/3279
2023-03-18 20:49:02 +08:00
2dust
4f120e8eb4 bug fixes 2023-03-17 17:20:40 +08:00
2dust
08aebf5736 up 6.18 2023-03-17 13:53:14 +08:00
2dust
5a4966ba8d Adjust speed test 2023-03-17 10:32:56 +08:00
2dust
9ba963fc45 bug fixes 2023-03-16 20:11:10 +08:00
2dust
ccc10dbae4 Merge pull request #3493 from ShiinaRinne/AddEnableHWA
Add: 设置中添加"启用硬件加速"的选项
2023-03-16 14:10:20 +08:00
ShiinaRinne
d858342269 Add: 设置中添加"启用硬件加速"的选项 2023-03-15 23:27:51 +08:00
2dust
63f251d1fd up 6.17 2023-03-10 20:38:08 +08:00
2dust
83efe66f3e bug fixes 2023-03-10 11:25:34 +08:00
2dust
3f5729044f up 6.16 2023-03-09 21:02:41 +08:00
2dust
045af7e8df Add reality and remove legacy xtls settings 2023-03-09 20:57:12 +08:00
2dust
6f181053b2 Optimize 2023-03-08 20:39:50 +08:00
2dust
4ff1dc2982 code cleanup 2023-03-07 20:24:51 +08:00
2dust
a883ba8808 Optimize add and delete performance 2023-03-07 20:24:26 +08:00
2dust
961bd6140c bug fixes 2023-03-06 20:08:21 +08:00
2dust
5f364b48c9 Enable themes for Windows common controls and dialogs 2023-03-05 20:08:48 +08:00
2dust
5a04911c7c fix resx 2023-03-05 20:05:39 +08:00
2dust
8ff248aa62 bug fixes 2023-03-05 20:04:31 +08:00
2dust
046ac95dc3 bug fixes 2023-03-05 19:51:26 +08:00
2dust
6fb17a4b74 Merge pull request #3419 from hxdhttk/hxdhttk/simulateToolTip
Add a control to simulate system tool tip.
2023-03-05 19:29:58 +08:00
Minghao Hu
f84397393d Niche. 2023-03-05 14:19:59 +08:00
Minghao Hu
800c93e2aa Add a control to simulate system tool tip. 2023-03-05 13:57:58 +08:00
2dust
df6179a1a8 Merge pull request #3405 from hvvvvvvv/master
优化全局热键相关代码和机制
2023-03-04 20:12:54 +08:00
hvvvvvvv
3e3a079ba1 Merge branch '2dust:master' into master 2023-03-04 18:22:08 +08:00
chao wan
0bf4a43663 删除调试代码 2023-03-04 11:52:46 +08:00
chao wan
5e9f4ad926 解决当前已注册热键无法触发UI线程控件的KeyDown事件的问题 2023-03-04 11:46:36 +08:00
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
chao wan
ba702ba041 热键相关代码更新 2023-03-04 00:40:06 +08:00
chao wan
c40d88d0b6 优化热键相关代码(未完成) 2023-03-03 18:03:29 +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
88 changed files with 3457 additions and 2881 deletions

1
.gitignore vendored
View File

@@ -16,3 +16,4 @@
/v2rayN/v2rayUpgrade/bin/Release
/v2rayN/v2rayUpgrade/obj/
*.user
/.vs/v2rayN

View File

@@ -1,5 +1,5 @@
# v2rayN
A V2Ray client for Windows, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core)
A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master)
@@ -7,15 +7,16 @@ A V2Ray client for Windows, support [Xray core](https://github.com/XTLS/Xray-cor
[![GitHub Releases](https://img.shields.io/github/downloads/2dust/v2rayN/latest/total?logo=github)](https://github.com/2dust/v2rayN/releases)
[![Chat on Telegram](https://img.shields.io/badge/Chat%20on-Telegram-brightgreen.svg)](https://t.me/v2rayn)
### How to use
- If you are new to this, please download v2rayN-Core.zip from [releases](https://github.com/2dust/v2rayN/releases)
- Otherwise please download v2rayN.zip (you will also need to download v2ray core into the same folder with v2rayN.exe)
## How to use
- If you are new to this, please download v2rayN-With-Core.zip from [releases](https://github.com/2dust/v2rayN/releases)
- Otherwise please download v2rayN.zip (you will also need to download cores in the bin directory)
- Run v2rayN.exe
### Requirements
- Microsoft [.NET Framework 4.8 Runtime](https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net48-offline-installer)
- v2fly core [https://github.com/v2fly/v2ray-core/releases](https://github.com/v2fly/v2ray-core/releases)
- Xray core [https://github.com/XTLS/Xray-core/releases](https://github.com/XTLS/Xray-core/releases)
## Requirements
- [Microsoft .NET 6.0 Desktop Runtime ](https://download.visualstudio.microsoft.com/download/pr/513d13b7-b456-45af-828b-b7b7981ff462/edf44a743b78f8b54a2cec97ce888346/windowsdesktop-runtime-6.0.15-win-x64.exe)
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
### Telegram Channel
## Telegram Channel
[github_2dust](https://t.me/github_2dust)

View File

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

View File

@@ -9,13 +9,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf">
<Version>3.21.9</Version>
</PackageReference>
<PackageReference Include="Grpc.Core">
<Version>2.46.5</Version>
</PackageReference>
<PackageReference Include="Grpc.Tools" Version="2.50.0">
<PackageReference Include="Google.Protobuf" Version="3.22.3" />
<PackageReference Include="Grpc.Core" Version="2.46.6" />
<PackageReference Include="Grpc.Tools" Version="2.53.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

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

View File

@@ -1,4 +1,5 @@
using System.Windows;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Threading;
using v2rayN.Handler;
using v2rayN.Mode;
@@ -30,8 +31,9 @@ namespace v2rayN
{
Global.ExePathKey = Utils.GetMD5(Utils.GetExePath());
var rebootas = (e.Args ?? new string[] { }).Any(t => t == Global.RebootAs);
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew);
if (!bCreatedNew)
if (!rebootas && !bCreatedNew)
{
ProgramStarted.Set();
Current.Shutdown();
@@ -42,10 +44,11 @@ namespace v2rayN
Global.processJob = new Job();
Logging.Setup();
Init();
Logging.LoggingEnabled(_config.guiItem.enableLog);
Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
Logging.ClearLogs();
Init();
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
@@ -62,6 +65,10 @@ namespace v2rayN
Environment.Exit(0);
return;
}
if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64)
{
_config.guiItem.enableStatistics = false;
}
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
@@ -77,7 +84,7 @@ namespace v2rayN
}
}
private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
{
Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
}

View File

@@ -6,14 +6,10 @@ namespace v2rayN.Base
{
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 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))
{
@@ -23,7 +19,7 @@ namespace v2rayN.Base
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000);
Uri uri = new Uri(url);
Uri uri = new(url);
//Authorization Header
var headers = new WebHeaderCollection();
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) =>
{
if (value.Error != null)
{
throw new Exception(string.Format("{0}", value.Error.Message));
throw value.Error;
}
};
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;
return text;
return reader.ReadToEnd();
}
@@ -73,7 +61,7 @@ namespace v2rayN.Base
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
throw new ArgumentNullException(nameof(url));
}
var cancellationToken = new CancellationTokenSource();
@@ -94,8 +82,7 @@ namespace v2rayN.Base
int totalSecond = 0;
var hasValue = false;
double maxSpeed = 0;
using (var downloader = new DownloadService(downloadOpt))
{
using var downloader = new DownloadService(downloadOpt);
//downloader.DownloadStarted += (sender, value) =>
//{
// if (progress != null)
@@ -128,23 +115,22 @@ namespace v2rayN.Base
}
}
};
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;
}
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))
{
throw new ArgumentNullException("url");
throw new ArgumentNullException(nameof(url));
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("fileName");
throw new ArgumentNullException(nameof(fileName));
}
if (File.Exists(fileName))
{
@@ -167,14 +153,10 @@ namespace v2rayN.Base
var progressPercentage = 0;
var hasValue = false;
using (var downloader = new DownloadService(downloadOpt))
{
using var downloader = new DownloadService(downloadOpt);
downloader.DownloadStarted += (sender, value) =>
{
if (progress != null)
{
progress.Report(0);
}
progress?.Report(0);
};
downloader.DownloadProgressChanged += (sender, value) =>
{
@@ -198,7 +180,6 @@ namespace v2rayN.Base
};
await downloader.DownloadFileTaskAsync(url, fileName, cancellationToken: cancellationToken.Token);
}
downloadOpt = null;
}

View File

@@ -1,6 +1,7 @@
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
namespace v2rayN.Base
{
@@ -8,159 +9,101 @@ namespace v2rayN.Base
/// </summary>
public class HttpClientHelper
{
private static HttpClientHelper httpClientHelper = null;
private HttpClient httpClient;
private readonly static Lazy<HttpClientHelper> _instance = new(() =>
{
HttpClientHandler handler = new() { UseCookies = false };
HttpClientHelper helper = new(new HttpClient(handler));
return helper;
});
public static HttpClientHelper Instance => _instance.Value;
private readonly HttpClient httpClient;
/// <summary>
/// </summary>
private HttpClientHelper() { }
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
/// <summary>
/// </summary>
/// <returns></returns>
public static HttpClientHelper GetInstance()
public async Task<string?> GetAsync(string url)
{
if (httpClientHelper != null)
{
return httpClientHelper;
if (string.IsNullOrEmpty(url)) return null;
return await httpClient.GetStringAsync(url);
}
else
{
HttpClientHelper httpClientHelper = new HttpClientHelper();
HttpClientHandler handler = new HttpClientHandler() { UseCookies = false };
httpClientHelper.httpClient = new HttpClient(handler);
return httpClientHelper;
}
}
public async Task<string> GetAsync(string url)
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
{
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)
{
if (string.IsNullOrEmpty(url))
{
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();
if (string.IsNullOrWhiteSpace(url)) return null;
return await client.GetStringAsync(url, token);
}
public async Task PutAsync(string url, Dictionary<string, string> headers)
{
var myContent = Utils.ToJson(headers);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var jsonContent = Utils.ToJson(headers);
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.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))
{
throw new ArgumentNullException("url");
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("fileName");
}
if (File.Exists(fileName))
{
File.Delete(fileName);
}
ArgumentNullException.ThrowIfNull(url);
ArgumentNullException.ThrowIfNull(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)
{
throw new Exception(string.Format("{0}", response.StatusCode));
}
if (!response.IsSuccessStatusCode) 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 ?? -1L;
var canReportProgress = total != -1 && progress != null;
using (var stream = await response.Content.ReadAsStreamAsync())
{
using (var file = File.Create(fileName))
{
using var stream = await response.Content.ReadAsStreamAsync(token);
using var file = File.Create(fileName);
var totalRead = 0L;
var buffer = new byte[1024 * 1024];
var isMoreToRead = true;
var progressPercentage = 0;
do
while (true)
{
token.ThrowIfCancellationRequested();
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);
var read = await stream.ReadAsync(buffer, token);
totalRead += read;
if (read == 0) break;
file.Write(buffer, 0, read);
if (canReportProgress)
{
var percent = Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
if (progressPercentage != percent && percent % 10 == 0)
var percent = (int)(100.0 * totalRead / total);
//if (progressPercentage != percent && percent % 10 == 0)
{
progressPercentage = percent;
progress.Report(percent);
progress!.Report(percent);
}
}
}
} while (isMoreToRead);
file.Close();
if (canReportProgress)
{
progress.Report(101);
progress!.Report(101);
}
}
}
}
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token)
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException("url");
throw new ArgumentNullException(nameof(url));
}
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
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 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;
@@ -182,7 +125,7 @@ namespace v2rayN.Base
}
}
var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
var read = await stream.ReadAsync(buffer, token);
if (read == 0)
{
@@ -210,7 +153,6 @@ namespace v2rayN.Base
}
} 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
{
private static readonly Lazy<SqliteHelper> _instance = new Lazy<SqliteHelper>(() => new());
private static readonly Lazy<SqliteHelper> _instance = new(() => new());
public static SqliteHelper Instance => _instance.Value;
private string _connstr;
public SQLiteConnection _db;
public SQLiteAsyncConnection _dbAsync;
private SQLiteConnection _db;
private SQLiteAsyncConnection _dbAsync;
private static readonly object objLock = new();
public SqliteHelper()
{
@@ -24,40 +25,59 @@ namespace v2rayN.Base
return _db.CreateTable<T>();
}
public int Add(object model)
public int Insert(object model)
{
return _db.Insert(model);
}
public async Task<int> AddAsync(object model)
public int InsertAll(IEnumerable models)
{
lock (objLock)
{
return _db.InsertAll(models);
}
}
public async Task<int> InsertAsync(object model)
{
return await _dbAsync.InsertAsync(model);
}
public int Replace(object model)
{
lock (objLock)
{
return _db.InsertOrReplace(model);
}
}
public async Task<int> Replacesync(object model)
{
return await _dbAsync.InsertOrReplaceAsync(model);
}
public int Update(object model)
{
lock (objLock)
{
return _db.Update(model);
}
}
public async Task<int> UpdateAsync(object model)
{
return await _dbAsync.UpdateAsync(model);
}
public int UpdateAll(IEnumerable models)
{
lock (objLock)
{
return _db.UpdateAll(models);
}
}
public int Delete(object model)
{
lock (objLock)
{
return _db.Delete(model);
}
}
public async Task<int> DeleteAsync(object model)
{
return await _dbAsync.DeleteAsync(model);

View File

@@ -1,15 +1,16 @@
using System.IO;
using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace v2rayN.Base
{
static class StringEx
{
public static bool IsNullOrEmpty(this string value)
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? 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);
}
@@ -34,7 +35,7 @@ namespace v2rayN.Base
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
{
string line;
string? line;
while ((line = reader.ReadLine()) != null)
{
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();
}

View File

@@ -17,7 +17,7 @@ namespace v2rayN.Converters
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;
}

View File

@@ -21,10 +21,7 @@ namespace v2rayN.Converters
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 v2raySampleInbound = "v2rayN.Sample.SampleInbound";
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 DefaultNetwork = "tcp";
@@ -42,7 +43,7 @@
public const string directTag = "direct";
public const string blockTag = "block";
public const string StreamSecurity = "tls";
public const string StreamSecurityX = "xtls";
public const string StreamSecurityReality = "reality";
public const string InboundSocks = "socks";
public const string InboundHttp = "http";
public const string InboundSocks2 = "socks2";
@@ -79,27 +80,28 @@
public const string DelayUnit = "";
public const string SpeedUnit = "";
public const int MinFontSize = 10;
public const string RebootAs = "rebootas";
public static readonly List<string> IEProxyProtocols = new List<string> {
public static readonly List<string> IEProxyProtocols = new() {
"{ip}:{http_port}",
"socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
""
};
public static readonly List<string> vmessSecuritys = new List<string> { "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> 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> 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> 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> networks = new List<string> { "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> coreTypes = new List<string> { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
public static readonly List<string> domainStrategys = new List<string> { "AsIs", "IPIfNonMatch", "IPOnDemand" };
public static readonly List<string> domainMatchers = new List<string> { "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> userAgent = new List<string> { "chrome", "firefox", "safari", "edge", "none" };
public static readonly Dictionary<string, string> userAgentTxt = new Dictionary<string, string>
public static readonly List<string> vmessSecuritys = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
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() { "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() { "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> flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
public static readonly List<string> networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" };
public static readonly List<string> kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
public static readonly List<string> coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5" };
public static readonly List<string> domainStrategys = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
public static readonly List<string> domainMatchers = new() { "linear", "mph", "" };
public static readonly List<string> fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
public static readonly List<string> userAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
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" },
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
@@ -107,23 +109,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" },
{"none",""}
};
public static readonly List<string> allowInsecures = new List<string> { "true", "false", "" };
public static readonly List<string> domainStrategy4Freedoms = new List<string> { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
public static readonly List<string> Languages = new List<string> { "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> LogLevel = new List<string> { "debug", "info", "warning", "error", "none" };
public static readonly List<string> InboundTags = new List<string> { "socks", "http", "socks2", "http2" };
public static readonly List<string> Protocols = new List<string> { "http", "tls", "bittorrent" };
public static readonly List<string> TunMtus = new List<string> { "9000", "1500" };
public static readonly List<string> TunStacks = new List<string> { "gvisor", "system" };
public static readonly List<string> PresetMsgFilters = new List<string> { "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> allowInsecures = new() { "true", "false", "" };
public static readonly List<string> domainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
public static readonly List<string> Languages = new() { "zh-Hans", "en", "fa-Ir", "ru" };
public static readonly List<string> alpns = new() { "h2", "http/1.1", "h2,http/1.1", "" };
public static readonly List<string> LogLevel = new() { "debug", "info", "warning", "error", "none" };
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
public static readonly List<string> Protocols = new() { "http", "tls", "bittorrent" };
public static readonly List<string> TunMtus = new() { "9000", "1500" };
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
public static readonly List<string> SpeedTestUrls = new() { @"http://cachefly.cachefly.net/100mb.test", @"http://cachefly.cachefly.net/10mb.test" };
#endregion
#region global variable
public static bool reloadCore { get; set; }
public static int statePort { get; set; }
public static Job processJob { get; set; }
public static bool ShowInTaskbar { get; set; }

View File

@@ -13,7 +13,7 @@ namespace v2rayN.Handler
class ConfigHandler
{
private static string configRes = Global.ConfigFileName;
private static readonly object objLock = new object();
private static readonly object objLock = new();
#region ConfigHandler
@@ -61,7 +61,7 @@ namespace v2rayN.Handler
if (config.inbound == null)
{
config.inbound = new List<InItem>();
InItem inItem = new InItem
InItem inItem = new()
{
protocol = Global.InboundSocks,
localPort = 10808,
@@ -151,9 +151,9 @@ namespace v2rayN.Handler
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))
{
@@ -190,22 +190,12 @@ namespace v2rayN.Handler
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;
}
if (config == null)
{
Global.reloadCore = false;
}
else
{
Global.reloadCore = true;
}
LazyConfig.Instance.SetConfig(ref config);
LazyConfig.Instance.SetConfig(config);
return 0;
}
/// <summary>
@@ -215,7 +205,6 @@ namespace v2rayN.Handler
/// <returns></returns>
public static int SaveConfig(ref Config config, bool reload = true)
{
Global.reloadCore = reload;
ToJsonFile(config);
@@ -363,7 +352,7 @@ namespace v2rayN.Handler
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddServer(ref Config config, ProfileItem profileItem)
public static int AddServer(ref Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.VMess;
@@ -381,7 +370,7 @@ namespace v2rayN.Handler
return -1;
}
AddServerCommon(ref config, profileItem);
AddServerCommon(ref config, profileItem, toFile);
return 0;
}
@@ -394,11 +383,15 @@ namespace v2rayN.Handler
/// <returns></returns>
public static int RemoveServer(Config config, List<ProfileItem> indexs)
{
var subid = "TempRemoveSubId";
foreach (var item in indexs)
{
RemoveProfileItem(config, item.indexId);
item.subid = subid;
}
SqliteHelper.Instance.UpdateAll(indexs);
RemoveServerViaSubid(ref config, subid, false);
return 0;
}
@@ -410,8 +403,14 @@ namespace v2rayN.Handler
/// <returns></returns>
public static int CopyServer(ref Config config, List<ProfileItem> indexs)
{
foreach (var item in indexs)
foreach (var it in indexs)
{
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
ProfileItem profileItem = Utils.DeepCopy(item);
profileItem.indexId = string.Empty;
profileItem.remarks = $"{item.remarks}-clone";
@@ -425,7 +424,7 @@ namespace v2rayN.Handler
}
else
{
AddServerCommon(ref config, profileItem);
AddServerCommon(ref config, profileItem, true);
}
}
@@ -438,49 +437,43 @@ namespace v2rayN.Handler
/// <param name="config"></param>
/// <param name="item"></param>
/// <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;
}
config.indexId = item.indexId;
Global.reloadCore = true;
config.indexId = indexId;
ToJsonFile(config);
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))
{
return 0;
}
if (SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.indexId == config.indexId).Count() > 0)
if (SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.indexId == config.indexId).Any())
{
return 0;
}
if (lstProfile.Count > 0)
{
return SetDefaultServer(ref config, lstProfile[0]);
return SetDefaultServerIndex(ref config, lstProfile.Where(t => t.port > 0).FirstOrDefault()?.indexId);
}
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
{
return SetDefaultServer(ref config, SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault());
return SetDefaultServerIndex(ref config, SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.port > 0).Select(t => t.indexId).FirstOrDefault());
}
return -1;
}
public static ProfileItem GetDefaultServer(ref Config config)
public static ProfileItem? GetDefaultServer(ref Config config)
{
var item = LazyConfig.Instance.GetProfileItem(config.indexId);
if (item is null)
{
var item2 = SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault();
SetDefaultServer(ref config, item2);
SetDefaultServerIndex(ref config, item2?.indexId);
return item2;
}
@@ -505,9 +498,10 @@ namespace v2rayN.Handler
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)
{
case EMove.Top:
@@ -516,7 +510,7 @@ namespace v2rayN.Handler
{
return 0;
}
lstProfile[index].sort = lstProfile[0].sort - 1;
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
break;
}
@@ -526,7 +520,7 @@ namespace v2rayN.Handler
{
return 0;
}
lstProfile[index].sort = lstProfile[index - 1].sort - 1;
sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
break;
}
@@ -537,7 +531,7 @@ namespace v2rayN.Handler
{
return 0;
}
lstProfile[index].sort = lstProfile[index + 1].sort + 1;
sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
break;
}
@@ -547,18 +541,16 @@ namespace v2rayN.Handler
{
return 0;
}
lstProfile[index].sort = lstProfile[lstProfile.Count - 1].sort + 1;
sort = ProfileExHandler.Instance.GetSort(lstProfile[^1].indexId) + 1;
break;
}
case EMove.Position:
lstProfile[index].sort = pos * 10 + 1;
sort = pos * 10 + 1;
break;
}
SqliteHelper.Instance.UpdateAll(lstProfile);
ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
return 0;
}
@@ -601,7 +593,7 @@ namespace v2rayN.Handler
}
AddServerCommon(ref config, profileItem);
AddServerCommon(ref config, profileItem, true);
return 0;
@@ -633,7 +625,7 @@ namespace v2rayN.Handler
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem)
public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.Shadowsocks;
@@ -646,7 +638,7 @@ namespace v2rayN.Handler
return -1;
}
AddServerCommon(ref config, profileItem);
AddServerCommon(ref config, profileItem, toFile);
return 0;
}
@@ -657,13 +649,13 @@ namespace v2rayN.Handler
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddSocksServer(ref Config config, ProfileItem profileItem)
public static int AddSocksServer(ref Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.Socks;
profileItem.address = profileItem.address.TrimEx();
AddServerCommon(ref config, profileItem);
AddServerCommon(ref config, profileItem, toFile);
return 0;
}
@@ -674,7 +666,7 @@ namespace v2rayN.Handler
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddTrojanServer(ref Config config, ProfileItem profileItem)
public static int AddTrojanServer(ref Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.Trojan;
@@ -684,25 +676,41 @@ namespace v2rayN.Handler
{
profileItem.streamSecurity = Global.StreamSecurity;
}
if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
{
profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
}
AddServerCommon(ref config, profileItem);
AddServerCommon(ref config, profileItem, toFile);
return 0;
}
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 lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
if (lstProfile.Count <= 0)
if (lstModel.Count <= 0)
{
return -1;
}
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
var lstProfile = (from t in lstModel
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
indexId = t.indexId,
configType = t.configType,
remarks = t.remarks,
address = t.address,
port = t.port,
security = t.security,
network = t.network,
streamSecurity = t.streamSecurity,
delay = t33 == null ? 0 : t33.delay,
speed = t33 == null ? 0 : t33.speed,
sort = t33 == null ? 0 : t33.sort
}).ToList();
Enum.TryParse(colName, true, out EServerColName name);
var propertyName = string.Empty;
switch (name)
{
@@ -713,10 +721,14 @@ namespace v2rayN.Handler
case EServerColName.security:
case EServerColName.network:
case EServerColName.streamSecurity:
case EServerColName.delay:
case EServerColName.speed:
propertyName = name.ToString();
break;
case EServerColName.delayVal:
propertyName = "delay";
break;
case EServerColName.speedVal:
propertyName = "speed";
break;
case EServerColName.subRemarks:
propertyName = "subid";
break;
@@ -736,33 +748,31 @@ namespace v2rayN.Handler
}
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;
foreach (var item in lstProfile)
{
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;
foreach (var item in lstProfile)
{
if (item.speed <= 0)
{
item.sort = maxSort;
ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
}
}
}
SqliteHelper.Instance.UpdateAll(lstProfile);
return 0;
}
@@ -772,7 +782,7 @@ namespace v2rayN.Handler
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddVlessServer(ref Config config, ProfileItem profileItem)
public static int AddVlessServer(ref Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.VLESS;
@@ -785,43 +795,56 @@ namespace v2rayN.Handler
profileItem.path = profileItem.path.TrimEx();
profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
AddServerCommon(ref config, profileItem);
if (!Global.flows.Contains(profileItem.flow))
{
profileItem.flow = Global.flows.First();
}
AddServerCommon(ref config, profileItem, toFile);
return 0;
}
public static int DedupServerList(ref Config config, ref List<ProfileItem> lstProfile)
public static Tuple<int, int> DedupServerList(Config config, string subId)
{
List<ProfileItem> source = lstProfile;
bool keepOlder = config.guiItem.keepOlderDedupl;
var lstProfile = LazyConfig.Instance.ProfileItems(subId);
List<ProfileItem> list = new List<ProfileItem>();
if (!keepOlder) source.Reverse(); // Remove the early items first
List<ProfileItem> lstKeep = new();
List<ProfileItem> lstRemove = new();
if (config.guiItem.keepOlderDedupl) lstProfile.Reverse();
foreach (ProfileItem item in source)
foreach (ProfileItem item in lstProfile)
{
if (!list.Exists(i => CompareProfileItem(i, item, false)))
if (!lstKeep.Exists(i => CompareProfileItem(i, item, false)))
{
list.Add(item);
lstKeep.Add(item);
}
else
{
RemoveProfileItem(config, item.indexId);
lstRemove.Add(item);
}
}
//if (!keepOlder) list.Reverse();
//config.vmess = list;
RemoveServer(config, lstRemove);
return list.Count;
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
}
public static int AddServerCommon(ref Config config, ProfileItem profileItem)
public static int AddServerCommon(ref Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configVersion = 2;
if (!Utils.IsNullOrEmpty(profileItem.streamSecurity))
{
if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
{
profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
}
if (Utils.IsNullOrEmpty(profileItem.fingerprint))
{
profileItem.fingerprint = config.coreBasicItem.defFingerprint;
}
}
if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network))
{
profileItem.network = Global.DefaultNetwork;
@@ -830,30 +853,16 @@ namespace v2rayN.Handler
if (Utils.IsNullOrEmpty(profileItem.indexId))
{
profileItem.indexId = Utils.GetGUID(false);
if (profileItem.sort <= 0)
{
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)
{
Global.reloadCore = true;
var maxSort = ProfileExHandler.Instance.GetMaxSort();
ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
}
if (SqliteHelper.Instance.Replace(profileItem) > 0)
if (toFile)
{
SqliteHelper.Instance.Replace(profileItem);
}
return 0;
}
else
{
return -1;
}
}
private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks)
{
@@ -862,8 +871,7 @@ namespace v2rayN.Handler
return false;
}
return o.configVersion == n.configVersion
&& o.configType == n.configType
return o.configType == n.configType
&& o.address == n.address
&& o.port == n.port
&& o.id == n.id
@@ -929,16 +937,18 @@ namespace v2rayN.Handler
}
int countServers = 0;
var maxSort = 0;
if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
//Check for duplicate indexId
List<string>? lstDbIndexId = null;
List<ProfileItem> lstAdd = new();
var arrData = clipboardData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
if (isSub)
{
maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort);
arrData = arrData.Distinct();
}
string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray());
foreach (string str in arrData)
{
//maybe sub
if (Utils.IsNullOrEmpty(subid) && (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol)))
if (!isSub && (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol)))
{
if (AddSubItem(ref config, str) == 0)
{
@@ -955,10 +965,23 @@ namespace v2rayN.Handler
//exist sub items
if (isSub && !Utils.IsNullOrEmpty(subid))
{
var existItem = lstOriSub?.FirstOrDefault(t => CompareProfileItem(t, profileItem, true));
var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub && CompareProfileItem(t, profileItem, true));
if (existItem != null)
{
profileItem = existItem;
//Check for duplicate indexId
if (lstDbIndexId is null)
{
lstDbIndexId = LazyConfig.Instance.ProfileItemIndexs("");
}
if (lstAdd.Any(t => t.indexId == existItem.indexId)
|| lstDbIndexId.Any(t => t == existItem.indexId))
{
profileItem.indexId = string.Empty;
}
else
{
profileItem.indexId = existItem.indexId;
}
}
//filter
if (!Utils.IsNullOrEmpty(subFilter))
@@ -971,43 +994,39 @@ namespace v2rayN.Handler
}
profileItem.subid = subid;
profileItem.isSub = isSub;
profileItem.sort = maxSort + countServers + 1;
var addStatus = -1;
if (profileItem.configType == EConfigType.VMess)
{
if (AddServer(ref config, profileItem) == 0)
{
countServers++;
}
addStatus = AddServer(ref config, profileItem, false);
}
else if (profileItem.configType == EConfigType.Shadowsocks)
{
if (AddShadowsocksServer(ref config, profileItem) == 0)
{
countServers++;
}
addStatus = AddShadowsocksServer(ref config, profileItem, false);
}
else if (profileItem.configType == EConfigType.Socks)
{
if (AddSocksServer(ref config, profileItem) == 0)
{
countServers++;
}
addStatus = AddSocksServer(ref config, profileItem, false);
}
else if (profileItem.configType == EConfigType.Trojan)
{
if (AddTrojanServer(ref config, profileItem) == 0)
{
countServers++;
}
addStatus = AddTrojanServer(ref config, profileItem, false);
}
else if (profileItem.configType == EConfigType.VLESS)
{
if (AddVlessServer(ref config, profileItem) == 0)
addStatus = AddVlessServer(ref config, profileItem, false);
}
if (addStatus == 0 && profileItem.port > 0)
{
countServers++;
lstAdd.Add(profileItem);
}
}
if (lstAdd.Count > 0)
{
SqliteHelper.Instance.InsertAll(lstAdd);
}
ToJsonFile(config);
@@ -1021,14 +1040,21 @@ namespace v2rayN.Handler
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
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData);
if (v2rayConfig != null
&& v2rayConfig.inbounds != null
&& v2rayConfig.inbounds.Count > 0
&& v2rayConfig.outbounds != null
&& v2rayConfig.outbounds.Count > 0)
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData);
if (v2rayConfig?.inbounds?.Count > 0
&& v2rayConfig.outbounds?.Count > 0)
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData);
@@ -1038,9 +1064,7 @@ namespace v2rayN.Handler
profileItem.remarks = "v2ray_custom";
}
//Is Clash configuration
else if (clipboardData.IndexOf("port") >= 0
&& clipboardData.IndexOf("socks-port") >= 0
&& clipboardData.IndexOf("proxies") >= 0)
else if (Containss(clipboardData, "port", "socks-port", "proxies"))
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
File.WriteAllText(fileName, clipboardData);
@@ -1050,12 +1074,7 @@ namespace v2rayN.Handler
profileItem.remarks = "clash_custom";
}
//Is hysteria configuration
else if (clipboardData.IndexOf("server") >= 0
&& clipboardData.IndexOf("up") >= 0
&& clipboardData.IndexOf("down") >= 0
&& clipboardData.IndexOf("listen") >= 0
&& clipboardData.IndexOf("<html>") < 0
&& clipboardData.IndexOf("<body>") < 0)
else if (Containss(clipboardData, "server", "up", "down", "listen", "<html>", "<body>"))
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData);
@@ -1065,10 +1084,7 @@ namespace v2rayN.Handler
profileItem.remarks = "hysteria_custom";
}
//Is naiveproxy configuration
else if (clipboardData.IndexOf("listen") >= 0
&& clipboardData.IndexOf("proxy") >= 0
&& clipboardData.IndexOf("<html>") < 0
&& clipboardData.IndexOf("<body>") < 0)
else if (Containss(clipboardData, "listen", "proxy", "<html>", "<body>"))
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
File.WriteAllText(fileName, clipboardData);
@@ -1092,7 +1108,7 @@ namespace v2rayN.Handler
{
RemoveServerViaSubid(ref config, subid, isSub);
}
if (isSub && lstOriSub != null && lstOriSub.Count == 1)
if (isSub && lstOriSub?.Count == 1)
{
profileItem.indexId = lstOriSub[0].indexId;
}
@@ -1129,16 +1145,16 @@ namespace v2rayN.Handler
//SsSIP008
var lstSsServer = Utils.FromJson<List<SsServer>>(clipboardData);
if (lstSsServer == null || lstSsServer.Count <= 0)
if (lstSsServer?.Count <= 0)
{
var ssSIP008 = Utils.FromJson<SsSIP008>(clipboardData);
if (ssSIP008?.servers != null && ssSIP008.servers.Count > 0)
if (ssSIP008?.servers?.Count > 0)
{
lstSsServer = ssSIP008.servers;
}
}
if (lstSsServer != null && lstSsServer.Count > 0)
if (lstSsServer?.Count > 0)
{
int counter = 0;
foreach (var it in lstSsServer)
@@ -1168,13 +1184,21 @@ namespace v2rayN.Handler
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))
{
lstOriSub = LazyConfig.Instance.ProfileItems(subid);
}
int counter = AddBatchServers(ref config, clipboardData, subid, isSub, lstOriSub);
var counter = 0;
if (Utils.IsBase64String(clipboardData))
{
counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
}
if (counter < 1)
{
counter = AddBatchServers(ref config, clipboardData, subid, isSub, lstOriSub);
}
if (counter < 1)
{
counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
@@ -1213,7 +1237,7 @@ namespace v2rayN.Handler
return 0;
}
SubItem subItem = new SubItem
SubItem subItem = new()
{
id = string.Empty,
remarks = "import_sub",
@@ -1262,6 +1286,7 @@ namespace v2rayN.Handler
{
return -1;
}
var customProfile = SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid && t.configType == EConfigType.Custom).ToList();
if (isSub)
{
SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'");
@@ -1270,6 +1295,10 @@ namespace v2rayN.Handler
{
SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'");
}
foreach (var item in customProfile)
{
File.Delete(Utils.GetConfigPath(item.address));
}
return 0;
}
@@ -1289,60 +1318,16 @@ namespace v2rayN.Handler
public static int MoveToGroup(Config config, List<ProfileItem> lstProfile, string subid)
{
foreach (var it in lstProfile)
foreach (var item in lstProfile)
{
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
continue;
}
item.subid = subid;
SqliteHelper.Instance.Update(item);
}
SqliteHelper.Instance.UpdateAll(lstProfile);
return 0;
}
#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
public static int SaveRoutingItem(ref Config config, RoutingItem item)
@@ -1488,8 +1473,6 @@ namespace v2rayN.Handler
config.routingBasicItem.routingIndexId = routingItem.id;
}
Global.reloadCore = true;
ToJsonFile(config);
return 0;
@@ -1512,7 +1495,7 @@ namespace v2rayN.Handler
var items = LazyConfig.Instance.RoutingItems();
if (blImportAdvancedRules || items.Count <= 0)
{
var maxSort = items.Max(t => t.sort);
var maxSort = items.Count;
//Bypass the mainland
var item2 = new RoutingItem()
{

View File

@@ -25,7 +25,7 @@ namespace v2rayN.Handler
/// <param name="msg"></param>
/// <param name="content"></param>
/// <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;
try
@@ -43,7 +43,7 @@ namespace v2rayN.Handler
}
else
{
V2rayConfig v2rayConfig = null;
V2rayConfig? v2rayConfig = null;
if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0)
{
return -1;
@@ -90,8 +90,8 @@ namespace v2rayN.Handler
{
var dtNow = DateTime.Now;
v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow.ToString("yyyy-MM-dd")}.txt");
v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow.ToString("yyyy-MM-dd")}.txt");
v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
}
else
{
@@ -114,11 +114,11 @@ namespace v2rayN.Handler
{
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);
//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);
if (config.inbound[0].allowLANConn)
@@ -157,7 +157,7 @@ namespace v2rayN.Handler
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);
if (Utils.IsNullOrEmpty(result))
@@ -184,8 +184,7 @@ namespace v2rayN.Handler
{
try
{
if (v2rayConfig.routing != null
&& v2rayConfig.routing.rules != null)
if (v2rayConfig.routing?.rules != null)
{
v2rayConfig.routing.domainStrategy = config.routingBasicItem.domainStrategy;
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.routingBasicItem.domainMatcher) ? null : config.routingBasicItem.domainMatcher;
@@ -241,25 +240,25 @@ namespace v2rayN.Handler
{
rules.port = null;
}
if (rules.domain != null && rules.domain.Count == 0)
if (rules.domain?.Count == 0)
{
rules.domain = null;
}
if (rules.ip != null && rules.ip.Count == 0)
if (rules.ip?.Count == 0)
{
rules.ip = null;
}
if (rules.protocol != null && rules.protocol.Count == 0)
if (rules.protocol?.Count == 0)
{
rules.protocol = null;
}
if (rules.inboundTag != null && rules.inboundTag.Count == 0)
if (rules.inboundTag?.Count == 0)
{
rules.inboundTag = null;
}
var hasDomainIp = false;
if (rules.domain != null && rules.domain.Count > 0)
if (rules.domain?.Count > 0)
{
var it = Utils.DeepCopy(rules);
it.ip = null;
@@ -275,7 +274,7 @@ namespace v2rayN.Handler
v2rayConfig.routing.rules.Add(it);
hasDomainIp = true;
}
if (rules.ip != null && rules.ip.Count > 0)
if (rules.ip?.Count > 0)
{
var it = Utils.DeepCopy(rules);
it.domain = null;
@@ -286,8 +285,8 @@ namespace v2rayN.Handler
if (!hasDomainIp)
{
if (!Utils.IsNullOrEmpty(rules.port)
|| (rules.protocol != null && rules.protocol.Count > 0)
|| (rules.inboundTag != null && rules.inboundTag.Count > 0)
|| (rules.protocol?.Count > 0)
|| (rules.inboundTag?.Count > 0)
)
{
var it = Utils.DeepCopy(rules);
@@ -405,7 +404,7 @@ namespace v2rayN.Handler
if (!Utils.IsNullOrEmpty(node.security)
&& !Utils.IsNullOrEmpty(node.id))
{
SocksUsersItem socksUsersItem = new SocksUsersItem
SocksUsersItem socksUsersItem = new()
{
user = node.security,
pass = node.id,
@@ -457,22 +456,8 @@ namespace v2rayN.Handler
boundStreamSettings(node, "out", outbound.streamSettings);
//if xtls
if (node.streamSecurity == Global.StreamSecurityX)
{
if (Utils.IsNullOrEmpty(node.flow))
{
usersItem.flow = Global.xtlsFlows[1];
}
else
{
usersItem.flow = node.flow.Replace("splice", "direct");
}
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
}
else if (node.streamSecurity == Global.StreamSecurity)
if (node.streamSecurity == Global.StreamSecurityReality
|| node.streamSecurity == Global.StreamSecurity)
{
if (!Utils.IsNullOrEmpty(node.flow))
{
@@ -506,22 +491,6 @@ namespace v2rayN.Handler
serversItem.ota = false;
serversItem.level = 1;
//if xtls
if (node.streamSecurity == Global.StreamSecurityX)
{
if (Utils.IsNullOrEmpty(node.flow))
{
serversItem.flow = Global.xtlsFlows[1];
}
else
{
serversItem.flow = node.flow.Replace("splice", "direct");
}
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
}
outbound.mux.enabled = false;
outbound.mux.concurrency = -1;
@@ -565,7 +534,7 @@ namespace v2rayN.Handler
{
streamSettings.security = node.streamSecurity;
TlsSettings tlsSettings = new TlsSettings
TlsSettings tlsSettings = new()
{
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(),
@@ -582,43 +551,38 @@ namespace v2rayN.Handler
streamSettings.tlsSettings = tlsSettings;
}
//if xtls
if (node.streamSecurity == Global.StreamSecurityX)
//if Reality
if (node.streamSecurity == Global.StreamSecurityReality)
{
streamSettings.security = node.streamSecurity;
TlsSettings xtlsSettings = new TlsSettings
TlsSettings realitySettings = new()
{
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(),
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint,
serverName = sni,
publicKey = node.publicKey,
shortId = node.shortId,
spiderX = node.spiderX,
};
if (!string.IsNullOrWhiteSpace(sni))
{
xtlsSettings.serverName = sni;
}
else if (!string.IsNullOrWhiteSpace(host))
{
xtlsSettings.serverName = Utils.String2List(host)[0];
}
streamSettings.xtlsSettings = xtlsSettings;
streamSettings.realitySettings = realitySettings;
}
//streamSettings
switch (node.GetNetwork())
{
case "kcp":
KcpSettings kcpSettings = new KcpSettings
KcpSettings kcpSettings = new()
{
mtu = config.kcpItem.mtu,
tti = config.kcpItem.tti
};
if (iobound.Equals("out"))
if (iobound == "out")
{
kcpSettings.uplinkCapacity = config.kcpItem.uplinkCapacity;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
}
else if (iobound.Equals("in"))
else if (iobound == "in")
{
kcpSettings.uplinkCapacity = config.kcpItem.downlinkCapacity; ;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
@@ -644,12 +608,8 @@ namespace v2rayN.Handler
break;
//ws
case "ws":
WsSettings wsSettings = new WsSettings
{
};
wsSettings.headers = new Headers
{
};
WsSettings wsSettings = new();
wsSettings.headers = new Headers();
string path = node.path;
if (!string.IsNullOrWhiteSpace(host))
{
@@ -665,17 +625,10 @@ namespace v2rayN.Handler
}
streamSettings.wsSettings = wsSettings;
//TlsSettings tlsSettings = new TlsSettings();
//tlsSettings.allowInsecure = config.allowInsecure();
//if (!string.IsNullOrWhiteSpace(host))
//{
// tlsSettings.serverName = host;
//}
//streamSettings.tlsSettings = tlsSettings;
break;
//h2
case "h2":
HttpSettings httpSettings = new HttpSettings();
HttpSettings httpSettings = new();
if (!string.IsNullOrWhiteSpace(host))
{
@@ -685,13 +638,10 @@ namespace v2rayN.Handler
streamSettings.httpSettings = httpSettings;
//TlsSettings tlsSettings2 = new TlsSettings();
//tlsSettings2.allowInsecure = config.allowInsecure();
//streamSettings.tlsSettings = tlsSettings2;
break;
//quic
case "quic":
QuicSettings quicsettings = new QuicSettings
QuicSettings quicsettings = new()
{
security = host,
key = node.path,
@@ -714,7 +664,7 @@ namespace v2rayN.Handler
}
break;
case "grpc":
var grpcSettings = new GrpcSettings
GrpcSettings grpcSettings = new()
{
serviceName = node.path,
multiMode = (node.headerType == Global.GrpcmultiMode),
@@ -723,14 +673,13 @@ namespace v2rayN.Handler
permit_without_stream = config.grpcItem.permit_without_stream,
initial_windows_size = config.grpcItem.initial_windows_size,
};
streamSettings.grpcSettings = grpcSettings;
break;
default:
//tcp
if (node.headerType.Equals(Global.TcpHeaderHttp))
if (node.headerType == Global.TcpHeaderHttp)
{
TcpSettings tcpSettings = new TcpSettings
TcpSettings tcpSettings = new()
{
header = new Header
{
@@ -738,7 +687,7 @@ namespace v2rayN.Handler
}
};
if (iobound.Equals("out"))
if (iobound == "out")
{
//request Host
string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName);
@@ -757,7 +706,7 @@ namespace v2rayN.Handler
request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
tcpSettings.header.request = Utils.FromJson<object>(request);
}
else if (iobound.Equals("in"))
else if (iobound == "in")
{
//string response = Utils.GetEmbedText(Global.v2raySampleHttpresponseFileName);
//tcpSettings.header.response = Utils.FromJson<object>(response);
@@ -793,13 +742,13 @@ namespace v2rayN.Handler
}
var obj = Utils.ParseJson(config.remoteDNS);
if (obj != null && obj.ContainsKey("servers"))
if (obj?.ContainsKey("servers") == true)
{
v2rayConfig.dns = obj;
}
else
{
List<string> servers = new List<string>();
List<string> servers = new();
string[] arrDNS = config.remoteDNS.Split(',');
foreach (string str in arrDNS)
@@ -828,9 +777,9 @@ namespace v2rayN.Handler
if (config.guiItem.enableStatistics)
{
string tag = Global.InboundAPITagName;
API apiObj = new API();
Policy policyObj = new Policy();
SystemPolicy policySystemSetting = new SystemPolicy();
API apiObj = new();
Policy policyObj = new();
SystemPolicy policySystemSetting = new();
string[] services = { "StatsService" };
@@ -847,8 +796,8 @@ namespace v2rayN.Handler
if (!v2rayConfig.inbounds.Exists(item => item.tag == tag))
{
Inbounds apiInbound = new Inbounds();
Inboundsettings apiInboundSettings = new Inboundsettings();
Inbounds apiInbound = new();
Inboundsettings apiInboundSettings = new();
apiInbound.tag = tag;
apiInbound.listen = Global.Loopback;
apiInbound.port = Global.statePort;
@@ -860,7 +809,7 @@ namespace v2rayN.Handler
if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag))
{
RulesItem apiRoutingRule = new RulesItem
RulesItem apiRoutingRule = new()
{
inboundTag = new List<string> { tag },
outboundTag = tag,
@@ -879,11 +828,11 @@ namespace v2rayN.Handler
/// <param name="fileName"></param>
/// <param name="msg"></param>
/// <returns></returns>
private static int GenerateClientCustomConfig(ProfileItem node, string fileName, out string msg)
private static int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
{
try
{
if (node == null)
if (node == null || fileName is null)
{
msg = ResUI.CheckServerSettings;
return -1;
@@ -957,11 +906,12 @@ namespace v2rayN.Handler
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
{
if (node == null)
if (node == null
|| node.port <= 0)
{
msg = ResUI.CheckServerSettings;
return -1;
@@ -1034,7 +984,7 @@ namespace v2rayN.Handler
return -1;
}
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
@@ -1123,10 +1073,10 @@ namespace v2rayN.Handler
#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;
ProfileItem profileItem = new ProfileItem();
ProfileItem profileItem = new();
try
{
@@ -1137,7 +1087,7 @@ namespace v2rayN.Handler
return null;
}
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null)
{
msg = ResUI.FailedConversionConfiguration;
@@ -1175,30 +1125,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp
if (outbound.streamSettings != null
&& outbound.streamSettings.network != null
if (outbound.streamSettings?.network != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.network))
{
profileItem.network = outbound.streamSettings.network;
}
//tcp http
if (outbound.streamSettings != null
&& outbound.streamSettings.tcpSettings != null
&& outbound.streamSettings.tcpSettings.header != null
if (outbound.streamSettings?.tcpSettings?.header != null
&& !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;
string request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request);
string? request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request))
{
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest?.headers?.Host?.Count > 0)
{
profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
}
@@ -1206,17 +1150,14 @@ namespace v2rayN.Handler
}
}
//kcp
if (outbound.streamSettings != null
&& outbound.streamSettings.kcpSettings != null
&& outbound.streamSettings.kcpSettings.header != null
if (outbound?.streamSettings?.kcpSettings?.header != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type))
{
profileItem.headerType = outbound.streamSettings.kcpSettings.header.type;
}
//ws
if (outbound.streamSettings != null
&& outbound.streamSettings.wsSettings != null)
if (outbound?.streamSettings?.wsSettings != null)
{
if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path))
{
@@ -1230,24 +1171,20 @@ namespace v2rayN.Handler
}
//h2
if (outbound.streamSettings != null
&& outbound.streamSettings.httpSettings != null)
if (outbound?.streamSettings?.httpSettings != null)
{
if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path))
{
profileItem.path = outbound.streamSettings.httpSettings.path;
}
if (outbound.streamSettings.httpSettings.host != null
&& outbound.streamSettings.httpSettings.host.Count > 0)
if (outbound.streamSettings.httpSettings.host?.Count > 0)
{
profileItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host);
}
}
//tls
if (outbound.streamSettings != null
&& outbound.streamSettings.security != null
&& outbound.streamSettings.security == Global.StreamSecurity)
if (outbound?.streamSettings?.security == Global.StreamSecurity)
{
profileItem.streamSecurity = Global.StreamSecurity;
}
@@ -1262,21 +1199,21 @@ namespace v2rayN.Handler
return profileItem;
}
public static ProfileItem ImportFromServerConfig(string fileName, out string msg)
public static ProfileItem? ImportFromServerConfig(string fileName, out string msg)
{
msg = string.Empty;
ProfileItem profileItem = new ProfileItem();
ProfileItem profileItem = new();
try
{
string result = Utils.LoadResource(fileName);
string? result = Utils.LoadResource(fileName);
if (Utils.IsNullOrEmpty(result))
{
msg = ResUI.FailedReadConfiguration;
return null;
}
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null)
{
msg = ResUI.FailedConversionConfiguration;
@@ -1313,30 +1250,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp
if (inbound.streamSettings != null
&& inbound.streamSettings.network != null
if (inbound.streamSettings?.network != null
&& !Utils.IsNullOrEmpty(inbound.streamSettings.network))
{
profileItem.network = inbound.streamSettings.network;
}
//tcp http
if (inbound.streamSettings != null
&& inbound.streamSettings.tcpSettings != null
&& inbound.streamSettings.tcpSettings.header != null
if (inbound.streamSettings?.tcpSettings?.header != null
&& !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;
string request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request);
string? request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request))
{
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest?.headers?.Host?.Count > 0)
{
profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
}
@@ -1353,8 +1284,7 @@ namespace v2rayN.Handler
//}
//ws
if (inbound.streamSettings != null
&& inbound.streamSettings.wsSettings != null)
if (inbound.streamSettings?.wsSettings != null)
{
if (!Utils.IsNullOrEmpty(inbound.streamSettings.wsSettings.path))
{
@@ -1368,24 +1298,20 @@ namespace v2rayN.Handler
}
//h2
if (inbound.streamSettings != null
&& inbound.streamSettings.httpSettings != null)
if (inbound.streamSettings?.httpSettings != null)
{
if (!Utils.IsNullOrEmpty(inbound.streamSettings.httpSettings.path))
{
profileItem.path = inbound.streamSettings.httpSettings.path;
}
if (inbound.streamSettings.httpSettings.host != null
&& inbound.streamSettings.httpSettings.host.Count > 0)
if (inbound.streamSettings.httpSettings.host?.Count > 0)
{
profileItem.requestHost = Utils.List2String(inbound.streamSettings.httpSettings.host);
}
}
//tls
if (inbound.streamSettings != null
&& inbound.streamSettings.security != null
&& inbound.streamSettings.security == Global.StreamSecurity)
if (inbound.streamSettings?.security == Global.StreamSecurity)
{
profileItem.streamSecurity = Global.StreamSecurity;
}
@@ -1401,7 +1327,7 @@ namespace v2rayN.Handler
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)
{
return -1;
@@ -1440,14 +1366,14 @@ namespace v2rayN.Handler
return "";
}
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result);
V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null)
{
msg = ResUI.FailedGenDefaultConfiguration;
return "";
}
List<IPEndPoint> lstIpEndPoints = new List<IPEndPoint>();
List<TcpConnectionInformation> lstTcpConns = new List<TcpConnectionInformation>();
List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new();
try
{
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
@@ -1459,7 +1385,7 @@ namespace v2rayN.Handler
Utils.SaveLog(ex.Message, ex);
}
log(configCopy, ref v2rayConfig, false);
log(configCopy, ref v2rayConfig, true);
//routing(config, ref v2rayConfig);
//dns(configCopy, ref v2rayConfig);
@@ -1477,7 +1403,7 @@ namespace v2rayN.Handler
{
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);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
@@ -1490,11 +1416,11 @@ namespace v2rayN.Handler
var port = httpPort;
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;
}
if (lstTcpConns != null && lstTcpConns.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{
continue;
}
@@ -1505,7 +1431,7 @@ namespace v2rayN.Handler
}
//Port In Used
if (lstIpEndPoints != null && lstIpEndPoints.FindIndex(_it => _it.Port == port) >= 0)
if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{
continue;
}
@@ -1513,7 +1439,7 @@ namespace v2rayN.Handler
it.allowTest = true;
//inbound
Inbounds inbound = new Inbounds
Inbounds inbound = new()
{
listen = Global.Loopback,
port = port,
@@ -1523,7 +1449,7 @@ namespace v2rayN.Handler
v2rayConfig.inbounds.Add(inbound);
//outbound
V2rayConfig v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
V2rayConfig? v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null)
{
@@ -1534,13 +1460,18 @@ namespace v2rayN.Handler
{
continue;
}
if (item.configType == EConfigType.VLESS
&& !Global.flows.Contains(item.flow))
{
continue;
}
outbound(item, ref v2rayConfigCopy);
v2rayConfigCopy.outbounds[0].tag = Global.agentTag + inbound.port.ToString();
v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]);
//rule
RulesItem rule = new RulesItem
RulesItem rule = new()
{
inboundTag = new List<string> { inbound.tag },
outboundTag = v2rayConfigCopy.outbounds[0].tag,

View File

@@ -12,9 +12,9 @@ namespace v2rayN.Handler
class CoreHandler
{
private static string _coreCConfigRes = Global.coreConfigFileName;
private CoreInfo _coreInfo;
private CoreInfo? _coreInfo;
private int _processId = 0;
private Process _process;
private Process? _process;
Action<bool, string> _updateFunc;
public CoreHandler(Action<bool, string> update)
@@ -26,8 +26,6 @@ namespace v2rayN.Handler
}
public void LoadCore(Config config)
{
if (Global.reloadCore)
{
var node = ConfigHandler.GetDefaultServer(ref config);
if (node == null)
@@ -69,7 +67,6 @@ namespace v2rayN.Handler
}
}
}
}
public int LoadCoreConfigString(Config config, List<ServerTestItem> _selecteds)
{
@@ -108,7 +105,7 @@ namespace v2rayN.Handler
Process[] existing = Process.GetProcessesByName(vName);
foreach (Process p in existing)
{
string path = p.MainModule.FileName;
string? path = p.MainModule?.FileName;
if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe")
{
KillProcess(p);
@@ -159,6 +156,7 @@ namespace v2rayN.Handler
if (Utils.IsNullOrEmpty(fileName))
{
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
Utils.SaveLog(msg);
ShowMsg(false, msg);
}
return fileName;
@@ -173,7 +171,8 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(_coreInfo);
if (fileName == "") return;
Process p = new Process
var displayLog = node.configType != EConfigType.Custom || node.displayLog;
Process p = new()
{
StartInfo = new ProcessStartInfo
{
@@ -181,18 +180,18 @@ namespace v2rayN.Handler
Arguments = _coreInfo.arguments,
WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false,
RedirectStandardOutput = node.displayLog,
RedirectStandardError = node.displayLog,
RedirectStandardOutput = displayLog,
RedirectStandardError = displayLog,
CreateNoWindow = true,
StandardOutputEncoding = node.displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = node.displayLog ? Encoding.UTF8 : null,
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
}
};
if (node.displayLog)
if (displayLog)
{
p.OutputDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
if (!string.IsNullOrEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
@@ -200,7 +199,7 @@ namespace v2rayN.Handler
};
}
p.Start();
if (node.displayLog)
if (displayLog)
{
p.BeginOutputReadLine();
}
@@ -208,13 +207,14 @@ namespace v2rayN.Handler
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);
}
catch (Exception ex)
{
//Utils.SaveLog(Utils.ToJson(node));
Utils.SaveLog(ex.Message, ex);
string msg = ex.Message;
ShowMsg(true, msg);
@@ -231,7 +231,7 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(coreInfo);
if (fileName == "") return -1;
Process p = new Process
Process p = new()
{
StartInfo = new ProcessStartInfo
{

View File

@@ -14,9 +14,9 @@ namespace v2rayN.Handler
/// </summary>
class DownloadHandle
{
public event EventHandler<ResultEventArgs> UpdateCompleted;
public event EventHandler<ResultEventArgs>? UpdateCompleted;
public event ErrorEventHandler Error;
public event ErrorEventHandler? Error;
public class ResultEventArgs : EventArgs
@@ -73,11 +73,7 @@ namespace v2rayN.Handler
var progress = new Progress<double>();
progress.ProgressChanged += (sender, value) =>
{
if (UpdateCompleted != null)
{
string msg = $"...{value}%";
UpdateCompleted(this, new ResultEventArgs(value > 100 ? true : false, msg));
}
UpdateCompleted?.Invoke(this, new ResultEventArgs(value > 100, $"...{value}%"));
};
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);
var webRequestHandler = new SocketsHttpHandler
@@ -107,10 +103,10 @@ namespace v2rayN.Handler
AllowAutoRedirect = false,
Proxy = GetWebProxy(blProxy)
};
HttpClient client = new HttpClient(webRequestHandler);
HttpClient client = new(webRequestHandler);
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();
}
@@ -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>
/// DownloadString
/// </summary>
/// <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
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
if (Utils.IsNullOrEmpty(userAgent))
{
userAgent = Utils.GetVersion(false);
}
var result = await DownloaderHelper.Instance.DownloadStringAsync(webProxy, url, userAgent, 30);
return result;
}
@@ -147,52 +257,8 @@ namespace v2rayN.Handler
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))
{
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)
public int RunAvailabilityCheck(IWebProxy? webProxy)
{
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;
responseTime = -1;
@@ -232,19 +298,14 @@ namespace v2rayN.Handler
myHttpWebRequest.Timeout = downloadTimeout * 1000;
myHttpWebRequest.Proxy = webProxy;
Stopwatch timer = new Stopwatch();
timer.Start();
Stopwatch timer = Stopwatch.StartNew();
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
if (myHttpWebResponse.StatusCode != HttpStatusCode.OK
&& myHttpWebResponse.StatusCode != HttpStatusCode.NoContent)
using HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
if (myHttpWebResponse.StatusCode is not HttpStatusCode.OK and not HttpStatusCode.NoContent)
{
msg = myHttpWebResponse.StatusDescription;
}
timer.Stop();
responseTime = timer.Elapsed.Milliseconds;
myHttpWebResponse.Close();
}
catch (Exception ex)
{
@@ -254,7 +315,7 @@ namespace v2rayN.Handler
return msg;
}
private WebProxy GetWebProxy(bool blProxy)
private WebProxy? GetWebProxy(bool blProxy)
{
if (!blProxy)
{
@@ -271,25 +332,17 @@ namespace v2rayN.Handler
private bool SocketCheck(string ip, int port)
{
Socket sock = null;
try
{
IPAddress ipa = IPAddress.Parse(ip);
IPEndPoint point = new IPEndPoint(ipa, port);
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint point = new(IPAddress.Parse(ip), port);
using Socket? sock = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(point);
return true;
}
catch { }
finally
catch (Exception)
{
if (sock != null)
{
sock.Close();
sock.Dispose();
}
}
return false;
}
}
}
}

View File

@@ -0,0 +1,172 @@
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Handler
{
public sealed class HotkeyHandler
{
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
public static HotkeyHandler Instance = _instance.Value;
private const int WmHotkey = 0x0312;
private Config _config
{
get => LazyConfig.Instance.GetConfig();
}
private Dictionary<int, List<EGlobalHotkey>> _hotkeyTriggerDic;
public bool IsPause { get; set; } = false;
public event Action<bool, string>? UpdateViewEvent;
public event Action<EGlobalHotkey>? HotkeyTriggerEvent;
public HotkeyHandler()
{
_hotkeyTriggerDic = new();
ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage;
Init();
}
private void Init()
{
_hotkeyTriggerDic.Clear();
if (_config.globalHotkeys == null) return;
foreach (var item in _config.globalHotkeys)
{
if (item.KeyCode != null && item.KeyCode != Key.None)
{
int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
KeyModifiers modifiers = KeyModifiers.None;
if (item.Control) modifiers |= KeyModifiers.Ctrl;
if (item.Shift) modifiers |= KeyModifiers.Shift;
if (item.Alt) modifiers |= KeyModifiers.Alt;
key = (key << 16) | (int)modifiers;
if (!_hotkeyTriggerDic.ContainsKey(key))
{
_hotkeyTriggerDic.Add(key, new() { item.eGlobalHotkey });
}
else
{
if (!_hotkeyTriggerDic[key].Contains(item.eGlobalHotkey))
_hotkeyTriggerDic[key].Add(item.eGlobalHotkey);
}
}
}
}
public void Load()
{
foreach (var _hotkeyCode in _hotkeyTriggerDic.Keys)
{
var hotkeyInfo = GetHotkeyInfo(_hotkeyCode);
bool isSuccess = false;
string msg;
Application.Current.Dispatcher.Invoke(() =>
{
isSuccess = RegisterHotKey(IntPtr.Zero, _hotkeyCode, hotkeyInfo.fsModifiers, hotkeyInfo.vKey);
});
foreach (var name in hotkeyInfo.Names)
{
if (isSuccess)
{
msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{name}({hotkeyInfo.hotkeyStr})");
}
else
{
var errInfo = new Win32Exception(Marshal.GetLastWin32Error()).Message;
msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{name}({hotkeyInfo.hotkeyStr})", errInfo);
}
UpdateViewEvent?.Invoke(false, msg);
}
}
}
public void ReLoad()
{
foreach (var hotkey in _hotkeyTriggerDic.Keys)
{
Application.Current.Dispatcher.Invoke(() =>
{
UnregisterHotKey(IntPtr.Zero, hotkey);
});
}
Init();
Load();
}
private (int fsModifiers, int vKey, string hotkeyStr, List<string> Names) GetHotkeyInfo(int hotkeycode)
{
var _fsModifiers = hotkeycode & 0xffff;
var _vkey = (hotkeycode >> 16) & 0xffff;
var _hotkeyStr = new StringBuilder();
var _names = new List<string>();
var mdif = (KeyModifiers)_fsModifiers;
var key = KeyInterop.KeyFromVirtualKey(_vkey);
if ((mdif | KeyModifiers.Ctrl) == KeyModifiers.Ctrl) _hotkeyStr.Append($"{KeyModifiers.Ctrl}+");
if ((mdif | KeyModifiers.Alt) == KeyModifiers.Alt) _hotkeyStr.Append($"{KeyModifiers.Alt}+");
if ((mdif | KeyModifiers.Shift) == KeyModifiers.Shift) _hotkeyStr.Append($"{KeyModifiers.Shift}+");
_hotkeyStr.Append(key.ToString());
foreach (var name in _hotkeyTriggerDic[hotkeycode])
{
_names.Add(name.ToString());
}
return (_fsModifiers, _vkey, _hotkeyStr.ToString(), _names);
}
private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled)
{
if (msg.message != WmHotkey || !_hotkeyTriggerDic.ContainsKey((int)msg.lParam))
{
return;
}
handled = true;
var _hotKeyCode = (int)msg.lParam;
if (IsPause)
{
Application.Current.Dispatcher.Invoke(() =>
{
UIElement? element = Keyboard.FocusedElement as UIElement;
if (element != null)
{
var _keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice,
PresentationSource.FromVisual(element), 0,
KeyInterop.KeyFromVirtualKey(GetHotkeyInfo(_hotKeyCode).vKey))
{
RoutedEvent = UIElement.KeyDownEvent
};
element.RaiseEvent(_keyEventArgs);
}
});
}
else
{
foreach (var keyEvent in _hotkeyTriggerDic[(int)msg.lParam])
{
HotkeyTriggerEvent?.Invoke(keyEvent);
}
}
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[Flags]
private enum KeyModifiers
{
None = 0x0000,
Alt = 0x0001,
Ctrl = 0x0002,
Shift = 0x0004,
Win = 0x0008,
NoRepeat = 0x4000
}
}
}

View File

@@ -5,7 +5,7 @@ namespace v2rayN.Handler
{
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 List<CoreInfo> coreInfos;
@@ -17,11 +17,12 @@ namespace v2rayN.Handler
SqliteHelper.Instance.CreateTable<ProfileItem>();
SqliteHelper.Instance.CreateTable<ServerStatItem>();
SqliteHelper.Instance.CreateTable<RoutingItem>();
SqliteHelper.Instance.CreateTable<ProfileExItem>();
}
#region Config
public void SetConfig(ref Config config)
public void SetConfig(Config config)
{
_config = config;
}
@@ -81,6 +82,18 @@ namespace v2rayN.Handler
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)
{
@@ -95,18 +108,17 @@ namespace v2rayN.Handler
}
if (!Utils.IsNullOrEmpty(filter))
{
if (filter.Contains("'"))
if (filter.Contains('\''))
{
filter = filter.Replace("'", "");
}
sql += $" and a.remarks like '%{filter}%'";
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
}
sql += " order by a.sort";
return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
}
public ProfileItem GetProfileItem(string indexId)
public ProfileItem? GetProfileItem(string indexId)
{
if (Utils.IsNullOrEmpty(indexId))
{
@@ -115,28 +127,6 @@ namespace v2rayN.Handler
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()
{
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)
{
if (profileItem != null && profileItem.coreType != null)
if (profileItem?.coreType != null)
{
return (ECoreType)profileItem.coreType;
}
@@ -183,16 +173,16 @@ namespace v2rayN.Handler
return item.coreType;
}
public CoreInfo GetCoreInfo(ECoreType coreType)
public CoreInfo? GetCoreInfo(ECoreType coreType)
{
if (coreInfos == null)
{
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)
{
@@ -203,15 +193,16 @@ namespace v2rayN.Handler
private void InitCoreInfo()
{
coreInfos = new List<CoreInfo>();
coreInfos = new(16);
coreInfos.Add(new CoreInfo
{
coreType = ECoreType.v2rayN,
coreUrl = Global.NUrl,
coreReleaseApiUrl = Global.NUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN.zip",
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip"
});
coreInfos.Add(new CoreInfo
@@ -223,6 +214,7 @@ namespace v2rayN.Handler
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray",
versionArg = "-version",
redirectInfo = true,
@@ -237,6 +229,7 @@ namespace v2rayN.Handler
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray",
versionArg = "version",
redirectInfo = true,
@@ -251,6 +244,7 @@ namespace v2rayN.Handler
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray",
versionArg = "version",
redirectInfo = true,
@@ -265,6 +259,7 @@ namespace v2rayN.Handler
coreReleaseApiUrl = Global.xrayCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
match = "Xray",
versionArg = "-version",
redirectInfo = true,
@@ -279,6 +274,7 @@ namespace v2rayN.Handler
coreReleaseApiUrl = Global.clashCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip",
coreDownloadUrlArm64 = Global.clashCoreUrl + "/download/{0}/clash-windows-arm64-{0}.zip",
match = "v",
versionArg = "-v",
redirectInfo = true,
@@ -293,6 +289,7 @@ namespace v2rayN.Handler
coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip",
coreDownloadUrlArm64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-arm64-{0}.zip",
match = "v",
versionArg = "-v",
redirectInfo = true,
@@ -307,6 +304,7 @@ namespace v2rayN.Handler
coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
coreDownloadUrlArm64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-arm64.exe",
redirectInfo = true,
});
@@ -335,6 +333,12 @@ namespace v2rayN.Handler
arguments = "run",
coreUrl = Global.singboxCoreUrl,
redirectInfo = true,
coreReleaseApiUrl = Global.singboxCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip",
coreDownloadUrl64 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
coreDownloadUrlArm64 = Global.singboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
match = "sing-box",
versionArg = "version",
});
}

View File

@@ -1,9 +1,7 @@
using NHotkey;
using NHotkey.Wpf;

using Microsoft.Win32;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using v2rayN.Mode;
using v2rayN.Resx;
@@ -12,15 +10,7 @@ namespace v2rayN.Handler
{
public sealed class MainFormHandler
{
private static readonly Lazy<MainFormHandler> instance = new Lazy<MainFormHandler>(() => new MainFormHandler());
//Action<bool, string> _updateUI;
//private DownloadHandle downloadHandle2;
//private Config _config;
//private V2rayHandler _v2rayHandler;
//private List<int> _selecteds;
//private Thread _workThread;
//Action<int, string> _updateFunc;
private static readonly Lazy<MainFormHandler> instance = new(() => new());
public static MainFormHandler Instance => instance.Value;
public Icon GetNotifyIcon(Config config)
@@ -42,19 +32,14 @@ namespace v2rayN.Handler
{
return new Icon(fileName);
}
switch (index)
return index switch
{
case 0:
return Properties.Resources.NotifyIcon1;
case 1:
return Properties.Resources.NotifyIcon2;
case 2:
return Properties.Resources.NotifyIcon3;
case 3:
return Properties.Resources.NotifyIcon2;
}
return Properties.Resources.NotifyIcon1;
0 => Properties.Resources.NotifyIcon1,
1 => Properties.Resources.NotifyIcon2,
2 => Properties.Resources.NotifyIcon3,
3 => Properties.Resources.NotifyIcon2,
_ => Properties.Resources.NotifyIcon1, // default
};
}
catch (Exception ex)
{
@@ -82,7 +67,7 @@ namespace v2rayN.Handler
return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute));
}
private Icon GetNotifyIcon4Routing(Config config)
private Icon? GetNotifyIcon4Routing(Config config)
{
try
{
@@ -107,9 +92,9 @@ namespace v2rayN.Handler
int width = 128;
int height = 128;
Bitmap bitmap = new Bitmap(width, height);
Bitmap bitmap = new(width, height);
Graphics graphics = Graphics.FromImage(bitmap);
SolidBrush drawBrush = new SolidBrush(color);
SolidBrush drawBrush = new(color);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height));
@@ -143,13 +128,13 @@ namespace v2rayN.Handler
return;
}
SaveFileDialog fileDialog = new SaveFileDialog
SaveFileDialog fileDialog = new()
{
Filter = "Config|*.json",
FilterIndex = 2,
RestoreDirectory = true
};
if (fileDialog.ShowDialog() != DialogResult.OK)
if (fileDialog.ShowDialog() != true)
{
return;
}
@@ -176,20 +161,19 @@ namespace v2rayN.Handler
{
return;
}
if (item.configType != EConfigType.VMess
&& item.configType != EConfigType.VLESS)
if (item.configType is not EConfigType.VMess and not EConfigType.VLESS)
{
UI.Show(ResUI.NonVmessService);
return;
}
SaveFileDialog fileDialog = new SaveFileDialog
SaveFileDialog fileDialog = new()
{
Filter = "Config|*.json",
FilterIndex = 2,
RestoreDirectory = true
};
if (fileDialog.ShowDialog() != DialogResult.OK)
if (fileDialog.ShowDialog() != true)
{
return;
}
@@ -212,21 +196,21 @@ namespace v2rayN.Handler
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)
{
fileName = Utils.GetBackupPath(fileName);
}
else
{
SaveFileDialog fileDialog = new SaveFileDialog
SaveFileDialog fileDialog = new()
{
FileName = fileName,
Filter = "guiNConfig|*.json",
FilterIndex = 2,
RestoreDirectory = true
};
if (fileDialog.ShowDialog() != DialogResult.OK)
if (fileDialog.ShowDialog() != true)
{
return;
}
@@ -254,14 +238,14 @@ namespace v2rayN.Handler
public bool RestoreGuiNConfig(ref Config config)
{
var fileContent = string.Empty;
using (OpenFileDialog fileDialog = new OpenFileDialog())
{
OpenFileDialog fileDialog = new();
fileDialog.InitialDirectory = Utils.GetBackupPath("");
fileDialog.Filter = "guiNConfig|*.json|All|*.*";
fileDialog.FilterIndex = 2;
fileDialog.RestoreDirectory = true;
if (fileDialog.ShowDialog() == DialogResult.OK)
if (fileDialog.ShowDialog() == true)
{
fileContent = Utils.LoadResource(fileDialog.FileName);
}
@@ -269,7 +253,7 @@ namespace v2rayN.Handler
{
return false;
}
}
if (Utils.IsNullOrEmpty(fileContent))
{
UI.ShowWarning(ResUI.OperationFailed);
@@ -286,44 +270,59 @@ namespace v2rayN.Handler
BackupGuiNConfig(config, true);
config = resConfig;
LazyConfig.Instance.SetConfig(ref config);
LazyConfig.Instance.SetConfig(config);
return true;
}
public void UpdateTask(Config config, Action<bool, string> update)
{
Task.Run(() => UpdateTaskRun(config, update));
Task.Run(() => UpdateTaskRunSubscription(config, update));
Task.Run(() => UpdateTaskRunGeo(config, update));
}
private void UpdateTaskRun(Config config, Action<bool, string> update)
private void UpdateTaskRunSubscription(Config config, Action<bool, string> update)
{
var autoUpdateSubTime = DateTime.Now;
var autoUpdateGeoTime = DateTime.Now;
Thread.Sleep(60000);
Utils.SaveLog("UpdateTaskRun");
Utils.SaveLog("UpdateTaskRunSubscription");
var updateHandle = new UpdateHandle();
while (true)
{
var dtNow = DateTime.Now;
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = LazyConfig.Instance.SubItems()
.Where(t => t.autoUpdateInterval > 0)
.Where(t => updateTime - t.updateTime >= t.autoUpdateInterval * 60)
.ToList();
if (config.guiItem.autoUpdateSubInterval > 0)
foreach (var item in lstSubs)
{
if ((dtNow - autoUpdateSubTime).Hours % config.guiItem.autoUpdateSubInterval == 0)
{
updateHandle.UpdateSubscriptionProcess(config, "", true, (bool success, string msg) =>
updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) =>
{
update(success, msg);
if (success)
Utils.SaveLog("subscription" + msg);
});
autoUpdateSubTime = dtNow;
item.updateTime = updateTime;
ConfigHandler.AddSubItem(ref config, item);
Thread.Sleep(5000);
}
Thread.Sleep(60000);
}
}
private void UpdateTaskRunGeo(Config config, Action<bool, string> update)
{
var autoUpdateGeoTime = DateTime.Now;
Thread.Sleep(1000 * 120);
Utils.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateHandle();
while (true)
{
var dtNow = DateTime.Now;
if (config.guiItem.autoUpdateInterval > 0)
{
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
@@ -349,48 +348,11 @@ namespace v2rayN.Handler
}
}
public void RegisterGlobalHotkey(Config config, EventHandler<HotkeyEventArgs> handler, Action<bool, string> update)
public void RegisterGlobalHotkey(Config config, Action<EGlobalHotkey> handler, Action<bool, string> update)
{
if (config.globalHotkeys == null)
{
return;
}
foreach (var item in config.globalHotkeys)
{
if (item.KeyCode == null)
{
continue;
}
var modifiers = ModifierKeys.None;
if (item.Control)
{
modifiers |= ModifierKeys.Control;
}
if (item.Alt)
{
modifiers |= ModifierKeys.Alt;
}
if (item.Shift)
{
modifiers |= ModifierKeys.Shift;
}
var gesture = new KeyGesture(KeyInterop.KeyFromVirtualKey((int)item.KeyCode), modifiers);
try
{
HotkeyManager.Current.AddOrReplace(((int)item.eGlobalHotkey).ToString(), gesture, handler);
var msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{item.eGlobalHotkey.ToString()}");
update(false, msg);
}
catch (Exception ex)
{
var msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{item.eGlobalHotkey.ToString()}", ex.Message);
update(false, msg);
Utils.SaveLog(msg);
}
}
HotkeyHandler.Instance.UpdateViewEvent += update;
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
HotkeyHandler.Instance.Load();
}
}

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);
}
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;
if (type == 1)
{
optionCount = 1;
}
else if (type == 2 || type == 4)
else if (type is 2 or 4)
{
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
}
@@ -71,12 +71,12 @@ namespace v2rayN.Handler
{
if (Environment.Is64BitOperatingSystem)
{
IntPtr opt = new IntPtr(optionsPtr.ToInt64() + (i * optSize));
IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
else
{
IntPtr opt = new IntPtr(optionsPtr.ToInt32() + (i * optSize));
IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
}
@@ -84,7 +84,7 @@ namespace v2rayN.Handler
list.options = optionsPtr;
// 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);
// and finally, call the API method!
@@ -189,24 +189,21 @@ namespace v2rayN.Handler
//判断是否使用代理
public static bool UsedProxy()
{
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
if (rk.GetValue("ProxyEnable").ToString() == "1")
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
if (rk?.GetValue("ProxyEnable")?.ToString() == "1")
{
rk.Close();
return true;
}
else
{
rk.Close();
return false;
}
}
//获得代理的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();
rk.Close();
return ProxyServer;
}

View File

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

View File

@@ -17,32 +17,22 @@ namespace v2rayN.Handler
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public static string GetShareUrl(ProfileItem item)
public static string? GetShareUrl(ProfileItem item)
{
try
{
string url = string.Empty;
string? url = string.Empty;
switch (item.configType)
url = item.configType switch
{
case EConfigType.VMess:
url = ShareVmess(item);
break;
case EConfigType.Shadowsocks:
url = ShareShadowsocks(item);
break;
case EConfigType.Socks:
url = ShareSocks(item);
break;
case EConfigType.Trojan:
url = ShareTrojan(item);
break;
case EConfigType.VLESS:
url = ShareVLESS(item);
break;
default:
break;
}
EConfigType.VMess => ShareVmess(item),
EConfigType.Shadowsocks => ShareShadowsocks(item),
EConfigType.Socks => ShareSocks(item),
EConfigType.Trojan => ShareTrojan(item),
EConfigType.VLESS => ShareVLESS(item),
_ => null,
};
return url;
}
catch (Exception ex)
@@ -56,10 +46,10 @@ namespace v2rayN.Handler
{
string url = string.Empty;
VmessQRCode vmessQRCode = new VmessQRCode
VmessQRCode vmessQRCode = new()
{
v = item.configVersion.ToString(),
ps = item.remarks.TrimEx(), //备注也许很长 ;
ps = item.remarks.TrimEx(),
add = item.address,
port = item.port.ToString(),
id = item.id,
@@ -177,7 +167,7 @@ namespace v2rayN.Handler
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))
{
@@ -207,6 +197,18 @@ namespace v2rayN.Handler
{
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
}
if (!Utils.IsNullOrEmpty(item.publicKey))
{
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
}
if (!Utils.IsNullOrEmpty(item.shortId))
{
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
}
if (!Utils.IsNullOrEmpty(item.spiderX))
{
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
}
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : "tcp");
@@ -260,7 +262,7 @@ namespace v2rayN.Handler
if (!Utils.IsNullOrEmpty(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));
}
@@ -278,13 +280,13 @@ namespace v2rayN.Handler
/// <summary>
/// 从剪贴板导入URL
/// </summary>
/// <param name="fileName"></param>
/// <param name="msg"></param>
/// <returns></returns>
public static ProfileItem ImportFromClipboardConfig(string clipboardData, out string msg)
public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
{
msg = string.Empty;
ProfileItem profileItem = new ProfileItem();
ProfileItem profileItem = new();
try
{
@@ -368,7 +370,7 @@ namespace v2rayN.Handler
return profileItem;
}
private static ProfileItem ResolveVmess(string result, out string msg)
private static ProfileItem? ResolveVmess(string result, out string msg)
{
msg = string.Empty;
var profileItem = new ProfileItem
@@ -376,11 +378,11 @@ namespace v2rayN.Handler
configType = EConfigType.VMess
};
result = result.Substring(Global.vmessProtocol.Length);
result = result[Global.vmessProtocol.Length..];
result = Utils.Base64Decode(result);
//转成Json
VmessQRCode vmessQRCode = Utils.FromJson<VmessQRCode>(result);
VmessQRCode? vmessQRCode = Utils.FromJson<VmessQRCode>(result);
if (vmessQRCode == null)
{
msg = ResUI.FailedConversionConfiguration;
@@ -418,17 +420,17 @@ namespace v2rayN.Handler
return profileItem;
}
private static ProfileItem ResolveVmess4Kitsunebi(string result)
private static ProfileItem? ResolveVmess4Kitsunebi(string result)
{
ProfileItem profileItem = new ProfileItem
ProfileItem profileItem = new()
{
configType = EConfigType.VMess
};
result = result.Substring(Global.vmessProtocol.Length);
result = result[Global.vmessProtocol.Length..];
int indexSplit = result.IndexOf("?");
if (indexSplit > 0)
{
result = result.Substring(0, indexSplit);
result = result[..indexSplit];
}
result = Utils.Base64Decode(result);
@@ -439,7 +441,7 @@ namespace v2rayN.Handler
}
string[] arr21 = arr1[0].Split(':');
string[] arr22 = arr1[1].Split(':');
if (arr21.Length != 2 || arr21.Length != 2)
if (arr21.Length != 2 || arr22.Length != 2)
{
return null;
}
@@ -456,15 +458,15 @@ namespace v2rayN.Handler
return profileItem;
}
private static ProfileItem ResolveStdVmess(string result)
private static ProfileItem? ResolveStdVmess(string result)
{
ProfileItem i = new ProfileItem
ProfileItem i = new()
{
configType = EConfigType.VMess,
security = "auto"
};
Uri u = new Uri(result);
Uri u = new(result);
i.address = u.IdnHost;
i.port = u.Port;
@@ -537,7 +539,7 @@ namespace v2rayN.Handler
return i;
}
private static ProfileItem ResolveSip002(string result)
private static ProfileItem? ResolveSip002(string result)
{
Uri parsedUrl;
try
@@ -548,7 +550,7 @@ namespace v2rayN.Handler
{
return null;
}
ProfileItem server = new ProfileItem
ProfileItem server = new()
{
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost,
@@ -556,7 +558,7 @@ namespace v2rayN.Handler
};
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
//2022-blake3
if (rawUserInfo.Contains(":"))
if (rawUserInfo.Contains(':'))
{
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
@@ -600,16 +602,16 @@ namespace v2rayN.Handler
return server;
}
private static readonly Regex UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase);
private static readonly Regex DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", 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(@"^((?<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);
if (!match.Success)
return null;
ProfileItem server = new ProfileItem();
ProfileItem server = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (!Utils.IsNullOrEmpty(tag))
@@ -635,16 +637,16 @@ namespace v2rayN.Handler
}
private static readonly Regex StdVmessUserInfo = new Regex(
@"^(?<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})$");
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})$", RegexOptions.Compiled);
private static ProfileItem ResolveSocks(string result)
private static ProfileItem? ResolveSocks(string result)
{
ProfileItem profileItem = new ProfileItem
ProfileItem profileItem = new()
{
configType = EConfigType.Socks
};
result = result.Substring(Global.socksProtocol.Length);
result = result[Global.socksProtocol.Length..];
//remark
int indexRemark = result.IndexOf("#");
if (indexRemark > 0)
@@ -654,7 +656,7 @@ namespace v2rayN.Handler
profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
}
catch { }
result = result.Substring(0, indexRemark);
result = result[..indexRemark];
}
//part decode
int indexS = result.IndexOf("@");
@@ -678,15 +680,15 @@ namespace v2rayN.Handler
{
return null;
}
profileItem.address = arr1[1].Substring(0, indexPort);
profileItem.port = Utils.ToInt(arr1[1].Substring(indexPort + 1, arr1[1].Length - (indexPort + 1)));
profileItem.address = arr1[1][..indexPort];
profileItem.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
profileItem.security = arr21[0];
profileItem.id = arr21[1];
return profileItem;
}
private static ProfileItem ResolveSocksNew(string result)
private static ProfileItem? ResolveSocksNew(string result)
{
Uri parsedUrl;
try
@@ -697,7 +699,7 @@ namespace v2rayN.Handler
{
return null;
}
ProfileItem server = new ProfileItem
ProfileItem server = new()
{
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost,
@@ -719,12 +721,12 @@ namespace v2rayN.Handler
private static ProfileItem ResolveTrojan(string result)
{
ProfileItem item = new ProfileItem
ProfileItem item = new()
{
configType = EConfigType.Trojan
};
Uri url = new Uri(result);
Uri url = new(result);
item.address = url.IdnHost;
item.port = url.Port;
@@ -738,13 +740,13 @@ namespace v2rayN.Handler
}
private static ProfileItem ResolveStdVLESS(string result)
{
ProfileItem item = new ProfileItem
ProfileItem item = new()
{
configType = EConfigType.VLESS,
security = "none"
};
Uri url = new Uri(result);
Uri url = new(result);
item.address = url.IdnHost;
item.port = url.Port;
@@ -766,6 +768,10 @@ namespace v2rayN.Handler
item.sni = query["sni"] ?? "";
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
item.network = query["type"] ?? "tcp";
switch (item.network)
{

View File

@@ -55,12 +55,16 @@ namespace v2rayN.Handler
case ESpeedActionType.Tcping:
case ESpeedActionType.Realping:
UpdateFunc(it.indexId, ResUI.Speedtesting, "");
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
break;
case ESpeedActionType.Speedtest:
UpdateFunc(it.indexId, "", ResUI.Speedtesting);
UpdateFunc(it.indexId, "", ResUI.SpeedtestingWait);
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break;
case ESpeedActionType.Mixedtest:
UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.Speedtesting);
UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.SpeedtestingWait);
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break;
}
}
@@ -117,7 +121,7 @@ namespace v2rayN.Handler
long time = Ping(it.address);
var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, "");
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output);
});
}
@@ -129,7 +133,7 @@ namespace v2rayN.Handler
int time = GetTcpingTime(it.address, it.port);
var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, "");
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output);
});
}
@@ -150,7 +154,7 @@ namespace v2rayN.Handler
DownloadHandle downloadHandle = new DownloadHandle();
//Thread.Sleep(5000);
List<Task> tasks = new List<Task>();
List<Task> tasks = new();
foreach (var it in _selecteds)
{
if (!it.allowTest)
@@ -165,12 +169,11 @@ namespace v2rayN.Handler
{
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);
LazyConfig.Instance.SetTestResult(it.indexId, output, "");
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output);
int.TryParse(output, out int delay);
it.delay = delay;
@@ -191,6 +194,7 @@ namespace v2rayN.Handler
finally
{
if (pid > 0) _coreHandler.CoreStopPid(pid);
ProfileExHandler.Instance.SaveTo();
}
return Task.CompletedTask;
@@ -214,7 +218,7 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new DownloadHandle();
DownloadHandle downloadHandle = new();
foreach (var it in _selecteds)
{
@@ -231,19 +235,20 @@ namespace v2rayN.Handler
// UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
// continue;
//}
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1");
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
UpdateFunc(it.indexId, "", ResUI.Speedtesting);
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
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) =>
{
decimal.TryParse(msg, out decimal dec);
if (dec > 0)
{
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", msg);
ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
}
UpdateFunc(it.indexId, "", msg);
});
@@ -254,6 +259,7 @@ namespace v2rayN.Handler
_coreHandler.CoreStopPid(pid);
}
UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
}
private async Task RunSpeedTestMulti()
@@ -269,7 +275,7 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new DownloadHandle();
DownloadHandle downloadHandle = new();
foreach (var it in _selecteds)
{
@@ -281,18 +287,19 @@ namespace v2rayN.Handler
{
continue;
}
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1");
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
UpdateFunc(it.indexId, "", ResUI.Speedtesting);
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
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) =>
{
decimal.TryParse(msg, out decimal dec);
if (dec > 0)
{
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", msg);
ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
}
UpdateFunc(it.indexId, "", msg);
});
@@ -306,6 +313,7 @@ namespace v2rayN.Handler
_coreHandler.CoreStopPid(pid);
}
UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
}
private async Task RunMixedtestAsync()
@@ -317,7 +325,7 @@ namespace v2rayN.Handler
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 output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
@@ -336,11 +344,11 @@ namespace v2rayN.Handler
ipAddress = ipHostInfo.AddressList[0];
}
Stopwatch timer = new Stopwatch();
Stopwatch timer = new();
timer.Start();
IPEndPoint endPoint = new IPEndPoint(ipAddress, port);
Socket clientSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new(ipAddress, port);
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
@@ -349,7 +357,6 @@ namespace v2rayN.Handler
timer.Stop();
responseTime = timer.Elapsed.Milliseconds;
clientSocket.Close();
}
catch (Exception ex)
{
@@ -371,7 +378,7 @@ namespace v2rayN.Handler
{
int timeout = 30;
int echoNum = 2;
Ping pingSender = new Ping();
using Ping pingSender = new();
for (int i = 0; i < echoNum; i++)
{
PingReply reply = pingSender.Send(host, timeout);

View File

@@ -13,7 +13,7 @@ namespace v2rayN.Handler
private Channel channel_;
private StatsService.StatsServiceClient client_;
private bool exitFlag_;
private ServerStatItem _serverStatItem;
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
public List<ServerStatItem> ServerStat => _lstServerStat;
@@ -70,7 +70,7 @@ namespace v2rayN.Handler
{
if (Enable && channel_.State == ChannelState.Ready)
{
QueryStatsResponse res = null;
QueryStatsResponse? res = null;
try
{
res = client_.QueryStats(new QueryStatsRequest() { Pattern = "", Reset = true });
@@ -134,6 +134,8 @@ namespace v2rayN.Handler
private void Init()
{
SqliteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
long ticks = DateTime.Now.Date.Ticks;
SqliteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{ticks}");
@@ -162,7 +164,7 @@ namespace v2rayN.Handler
todayDown = 0,
dateNow = ticks
};
_ = SqliteHelper.Instance.Replacesync(_serverStatItem);
SqliteHelper.Instance.Replace(_serverStatItem);
_lstServerStat.Add(_serverStatItem);
}
}
@@ -229,7 +231,7 @@ namespace v2rayN.Handler
try
{
// TCP stack please do me a favor
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
TcpListener l = new(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();

View File

@@ -20,7 +20,7 @@ namespace v2rayN.Handler
// <proxy-server><CR-LF>
// <bypass-list><CR-LF>
// <pac-url>
private static SysproxyConfig _userSettings = null;
private static SysproxyConfig? _userSettings = null;
enum RET_ERRORS : int
{
@@ -50,7 +50,7 @@ namespace v2rayN.Handler
{
var type = config.sysProxyType;
if (forceDisable && type == ESysProxyType.ForcedChange)
if (forceDisable && type != ESysProxyType.Unchanged)
{
type = ESysProxyType.ForcedClear;
}
@@ -154,11 +154,10 @@ namespace v2rayN.Handler
// using event to avoid hanging when redirect standard output/error
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
// and http://blog.csdn.net/zhangweixing0/article/details/7356841
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
using (Process process = new Process())
{
using AutoResetEvent outputWaitHandle = new(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;
@@ -174,8 +173,8 @@ namespace v2rayN.Handler
process.StartInfo.CreateNoWindow = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
StringBuilder output = new(1024);
StringBuilder error = new(1024);
process.OutputDataReceived += (sender, e) =>
{
@@ -232,8 +231,6 @@ namespace v2rayN.Handler
// _queryStr = stdout;
//}
}
}
}
}

View File

@@ -3,17 +3,18 @@ using System.IO;
using System.Reactive.Linq;
using v2rayN.Handler;
using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Base
{
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;
private string _tunConfigName = "tunConfig.json";
private static Config _config;
private CoreInfo coreInfo;
private Process _process;
private Process? _process;
private static int _socksPort;
private static bool _needRestart = true;
private static bool _isRunning = false;
@@ -44,7 +45,7 @@ namespace v2rayN.Base
{
var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
if (socksPort.Equals(_socksPort)
if (socksPort == _socksPort
&& _process != null
&& !_process.HasExited)
{
@@ -60,6 +61,7 @@ namespace v2rayN.Base
{
return;
}
CoreStartTest();
CoreStart();
}
}
@@ -101,6 +103,7 @@ namespace v2rayN.Base
configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}");
//logs
configStr = configStr.Replace("$log_disabled$", $"{(!_config.tunModeItem.enabledLog).ToString().ToLower()}");
if (_config.tunModeItem.showWindow)
{
configStr = configStr.Replace("$log_output$", $"");
@@ -108,16 +111,32 @@ namespace v2rayN.Base
else
{
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(@"\", @"\\")}");
}
//port
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
List<string> lstDnsExe = new List<string>();
List<string> lstDirectExe = new List<string>();
List<string> lstDnsExe = new();
List<string> lstDirectExe = new();
var coreInfos = LazyConfig.Instance.GetCoreInfos();
foreach (var it in coreInfos)
{
@@ -225,7 +244,8 @@ namespace v2rayN.Base
}
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;
}
@@ -235,12 +255,12 @@ namespace v2rayN.Base
try
{
string fileName = CoreFindexe();
if (fileName == "")
if (Utils.IsNullOrEmpty(fileName))
{
return;
}
var showWindow = _config.tunModeItem.showWindow;
Process p = new Process
Process p = new()
{
StartInfo = new ProcessStartInfo
{
@@ -293,5 +313,47 @@ namespace v2rayN.Base
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

@@ -1,9 +1,11 @@
using Splat;
using DynamicData;
using Splat;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Windows;
using v2rayN.Base;
using v2rayN.Mode;
using v2rayN.Resx;
@@ -35,11 +37,7 @@ namespace v2rayN.Handler
_updateFunc = update;
var url = string.Empty;
DownloadHandle downloadHandle = null;
if (downloadHandle == null)
{
downloadHandle = new DownloadHandle();
DownloadHandle downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
@@ -50,7 +48,7 @@ namespace v2rayN.Handler
{
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
fileName = Utils.UrlEncode(fileName);
Process process = new Process
Process process = new()
{
StartInfo = new ProcessStartInfo
{
@@ -79,7 +77,6 @@ namespace v2rayN.Handler
{
_updateFunc(false, args.GetException().Message);
};
}
AbsoluteCompleted += (sender2, args) =>
{
if (args.Success)
@@ -106,10 +103,7 @@ namespace v2rayN.Handler
_updateFunc = update;
var url = string.Empty;
DownloadHandle downloadHandle = null;
if (downloadHandle == null)
{
downloadHandle = new DownloadHandle();
DownloadHandle downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
@@ -135,7 +129,6 @@ namespace v2rayN.Handler
{
_updateFunc(true, args.GetException().Message);
};
}
AbsoluteCompleted += (sender2, args) =>
{
@@ -172,36 +165,22 @@ namespace v2rayN.Handler
Task.Run(async () =>
{
//Turn off system proxy
bool bSysProxyType = false;
if (!blProxy && config.sysProxyType == ESysProxyType.ForcedChange)
{
bSysProxyType = true;
config.sysProxyType = ESysProxyType.ForcedClear;
SysProxyHandle.UpdateSysProxy(config, false);
Thread.Sleep(3000);
}
foreach (var item in subItem)
{
if (item.enabled == false)
{
continue;
}
if (!Utils.IsNullOrEmpty(subId) && item.id != subId)
{
continue;
}
string id = item.id.TrimEx();
string url = item.url.TrimEx();
string userAgent = item.userAgent.TrimEx();
string hashCode = $"{item.remarks}->";
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url))
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (!Utils.IsNullOrEmpty(subId) && item.id != subId))
{
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
continue;
}
if (item.enabled == false)
{
_updateFunc(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}");
continue;
}
var downloadHandle = new DownloadHandle();
downloadHandle.Error += (sender2, args) =>
@@ -209,14 +188,53 @@ namespace v2rayN.Handler
_updateFunc(false, $"{hashCode}{args.GetException().Message}");
};
//idn to idc
url = Utils.GetPunycode(url);
_updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}");
var result = await downloadHandle.DownloadStringAsync(url, blProxy, userAgent);
//one url
url = Utils.GetPunycode(url);
var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent);
if (blProxy && Utils.IsNullOrEmpty(result))
{
result = await downloadHandle.DownloadStringAsync(url, false, userAgent);
result = await downloadHandle.TryDownloadString(url, false, userAgent);
}
//more url
if (!Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
{
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result))
{
result = Utils.Base64Decode(result);
}
var lstUrl = new List<string>
{
item.moreUrl.TrimEx().Split(",")
};
foreach (var it in lstUrl)
{
var url2 = Utils.GetPunycode(it);
if (Utils.IsNullOrEmpty(url2))
{
continue;
}
var result2 = await downloadHandle.TryDownloadString(url2, blProxy, userAgent);
if (blProxy && Utils.IsNullOrEmpty(result2))
{
result2 = await downloadHandle.TryDownloadString(url2, false, userAgent);
}
if (!Utils.IsNullOrEmpty(result2))
{
if (Utils.IsBase64String(result2))
{
result += Utils.Base64Decode(result2);
}
else
{
result += result2;
}
}
}
}
if (Utils.IsNullOrEmpty(result))
@@ -226,7 +244,7 @@ namespace v2rayN.Handler
else
{
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
if (result.Length < 99)
if (result!.Length < 99)
{
_updateFunc(false, $"{hashCode}{result}");
}
@@ -244,29 +262,19 @@ namespace v2rayN.Handler
}
_updateFunc(false, "-------------------------------------------------------");
}
//restore system proxy
if (bSysProxyType)
{
config.sysProxyType = ESysProxyType.ForcedChange;
SysProxyHandle.UpdateSysProxy(config, false);
}
_updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
});
}
public void UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
{
_config = config;
_updateFunc = update;
var url = string.Format(Global.geoUrl, geoName);
DownloadHandle downloadHandle = null;
if (downloadHandle == null)
{
downloadHandle = new DownloadHandle();
DownloadHandle downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
@@ -304,7 +312,6 @@ namespace v2rayN.Handler
{
_updateFunc(false, args.GetException().Message);
};
}
askToDownload(downloadHandle, url, false);
}
@@ -328,7 +335,7 @@ namespace v2rayN.Handler
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
string url = coreInfo.coreReleaseApiUrl;
var result = await (new DownloadHandle()).DownloadStringAsyncOri(url, true, "");
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, "");
if (!Utils.IsNullOrEmpty(result))
{
responseHandler(type, result, preRelease);
@@ -374,7 +381,7 @@ namespace v2rayN.Handler
return "";
}
Process p = new Process();
using Process p = new();
p.StartInfo.FileName = filePath;
p.StartInfo.Arguments = coreInfo.versionArg;
p.StartInfo.WorkingDirectory = Utils.StartupPath();
@@ -398,6 +405,9 @@ namespace v2rayN.Handler
case ECoreType.clash_meta:
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
break;
case ECoreType.sing_box:
version = Regex.Match(echo, $"([0-9.]+)").Groups[1].Value;
break;
}
return version;
}
@@ -436,7 +446,20 @@ namespace v2rayN.Handler
{
curVersion = "v" + getCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, curVersion);
string osBit = Environment.Is64BitProcess ? "64" : "32";
string osBit = "64";
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
osBit = "arm64-v8a";
break;
case Architecture.X86:
osBit = "32";
break;
default:
osBit = "64";
break;
}
url = string.Format(coreInfo.coreDownloadUrl64, version, osBit);
break;
}
@@ -445,23 +468,58 @@ namespace v2rayN.Handler
{
curVersion = getCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, curVersion);
if (Environment.Is64BitProcess)
switch (RuntimeInformation.ProcessArchitecture)
{
url = string.Format(coreInfo.coreDownloadUrl64, version);
case Architecture.Arm64:
url = coreInfo.coreDownloadUrlArm64;
break;
case Architecture.X86:
url = coreInfo.coreDownloadUrl32;
break;
default:
url = coreInfo.coreDownloadUrl64;
break;
}
else
url = string.Format(url, version);
break;
}
case ECoreType.sing_box:
{
url = string.Format(coreInfo.coreDownloadUrl32, version);
curVersion = "v" + getCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, curVersion);
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
url = coreInfo.coreDownloadUrlArm64;
break;
case Architecture.X86:
url = coreInfo.coreDownloadUrl32;
break;
default:
url = coreInfo.coreDownloadUrl64;
break;
}
url = string.Format(url, version, version.Replace("v", ""));
break;
}
case ECoreType.v2rayN:
{
curVersion = FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString();
message = string.Format(ResUI.IsLatestN, curVersion);
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
url = string.Format(coreInfo.coreDownloadUrlArm64, version);
break;
case Architecture.X86:
url = string.Format(coreInfo.coreDownloadUrl32, version);
break;
default:
url = string.Format(coreInfo.coreDownloadUrl64, version);
break;
}
break;
}
default:
throw new ArgumentException("Type");
}
@@ -497,7 +555,7 @@ namespace v2rayN.Handler
bool blDownload = false;
if (blAsk)
{
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == DialogResult.Yes)
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes)
{
blDownload = true;
}

View File

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

View File

@@ -1,5 +1,4 @@
using System.Windows.Forms;
using System.Windows.Input;
namespace v2rayN.Mode
{
[Serializable]
@@ -104,6 +103,10 @@ namespace v2rayN.Mode
public bool enableSecurityProtocolTls13 { get; set; }
public int trayMenuServersLimit { get; set; } = 20;
public bool enableHWA { get; set; } = false;
public bool enableLog { get; set; } = true;
}
[Serializable]
@@ -123,7 +126,8 @@ namespace v2rayN.Mode
public bool doubleClick2Activate { get; set; }
public bool autoHideStartup { get; set; } = true;
public string mainMsgFilter { get; set; }
public Dictionary<string, int> mainLvColWidth { get; set; }
public List<ColumnItem> mainColumnItem { get; set; }
}
[Serializable]
@@ -143,7 +147,7 @@ namespace v2rayN.Mode
public bool Shift { get; set; }
public Keys? KeyCode { get; set; }
public Key? KeyCode { get; set; }
}
@@ -160,6 +164,7 @@ namespace v2rayN.Mode
{
public bool enableTun { get; set; }
public bool showWindow { get; set; }
public bool enabledLog { get; set; }
public bool strictRoute { get; set; }
public string stack { get; set; }
public int mtu { get; set; }
@@ -167,8 +172,10 @@ namespace v2rayN.Mode
public bool bypassMode { get; set; } = true;
public List<string> directIP { get; set; }
public List<string> directProcess { get; set; }
public string directDNS { get; set; }
public List<string> proxyIP { get; set; }
public List<string> proxyProcess { get; set; }
public string proxyDNS { get; set; }
}
@@ -192,4 +199,12 @@ namespace v2rayN.Mode
public string routingIndexId { 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

@@ -301,7 +301,7 @@
get; set;
}
/// <summary>
/// 备注或别名
///
/// </summary>
public string remarks
{

View File

@@ -17,6 +17,8 @@
public string coreDownloadUrl64 { get; set; }
public string coreDownloadUrlArm64 { get; set; }
public string match { get; set; }
public string versionArg { get; set; }

View File

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

View File

@@ -0,0 +1,9 @@
namespace v2rayN.Mode
{
public enum EViewAction
{
AdjustMainLvColWidth,
ProfilesFocus
}
}

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;
configType = EConfigType.VMess;
configVersion = 2;
sort = 0;
address = string.Empty;
port = 0;
id = string.Empty;
@@ -86,166 +85,100 @@ namespace v2rayN.Mode
#endregion
[PrimaryKey]
public string indexId
{
get; set;
}
public string indexId { get; set; }
/// <summary>
/// config type(1=normal,2=custom)
/// </summary>
public EConfigType configType
{
get; set;
}
public EConfigType configType { get; set; }
/// <summary>
/// 版本(现在=2)
/// </summary>
public int configVersion
{
get; set;
}
public int sort
{
get; set;
}
public int configVersion { get; set; }
/// <summary>
/// 远程服务器地址
/// </summary>
public string address
{
get; set;
}
public string address { get; set; }
/// <summary>
/// 远程服务器端口
/// </summary>
public int port
{
get; set;
}
public int port { get; set; }
/// <summary>
/// 远程服务器ID
/// </summary>
public string id
{
get; set;
}
public string id { get; set; }
/// <summary>
/// 远程服务器额外ID
/// </summary>
public int alterId
{
get; set;
}
public int alterId { get; set; }
/// <summary>
/// 本地安全策略
/// </summary>
public string security
{
get; set;
}
public string security { get; set; }
/// <summary>
/// tcp,kcp,ws,h2,quic
/// </summary>
public string network
{
get; set;
}
public string network { get; set; }
/// <summary>
/// 备注或别名
///
/// </summary>
public string remarks
{
get; set;
}
public string remarks { get; set; }
/// <summary>
/// 伪装类型
/// </summary>
public string headerType
{
get; set;
}
public string headerType { get; set; }
/// <summary>
/// 伪装的域名
/// </summary>
public string requestHost
{
get; set;
}
public string requestHost { get; set; }
/// <summary>
/// ws h2 path
/// </summary>
public string path
{
get; set;
}
public string path { get; set; }
/// <summary>
/// 传输层安全
/// </summary>
public string streamSecurity
{
get; set;
}
public string streamSecurity { get; set; }
/// <summary>
/// 是否允许不安全连接(用于客户端)
/// </summary>
public string allowInsecure
{
get; set;
}
public int delay { get; set; }
public decimal speed { get; set; }
public string allowInsecure { get; set; }
/// <summary>
/// SubItem id
/// </summary>
public string subid
{
get; set;
}
public string subid { get; set; }
public bool isSub { get; set; } = true;
/// <summary>
/// VLESS flow
/// </summary>
public string flow
{
get; set;
}
public string flow { get; set; }
/// <summary>
/// tls sni
/// </summary>
public string sni
{
get; set;
}
public string sni { get; set; }
/// <summary>
/// tls alpn
/// </summary>
public string alpn { get; set; } = string.Empty;
public ECoreType? coreType
{
get; set;
}
public ECoreType? coreType { get; set; }
public int preSocksPort
{
get; set;
}
public int preSocksPort { get; set; }
public string fingerprint { get; set; }
public bool displayLog { get; set; } = true;
public string publicKey { get; set; }
public string shortId { get; set; }
public string spiderX { get; set; }
}
}

View File

@@ -5,6 +5,9 @@
{
public bool isActive { 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 speedVal { get; set; }
public string todayUp { get; set; }

View File

@@ -6,46 +6,24 @@ namespace v2rayN.Mode
public class SubItem
{
[PrimaryKey]
public string id
{
get; set;
}
public string id { get; set; }
/// <summary>
/// 备注
/// </summary>
public string remarks
{
get; set;
}
public string remarks { get; set; }
/// <summary>
/// url
/// </summary>
public string url
{
get; set;
}
public string url { get; set; }
public string moreUrl { get; set; }
/// <summary>
/// enable
/// </summary>
public bool enabled { get; set; } = true;
/// <summary>
///
/// </summary>
public string userAgent
{
get; set;
} = string.Empty;
public string userAgent { get; set; } = string.Empty;
public int sort { get; set; }
public int sort
{
get; set;
}
public string filter { get; set; }
public int autoUpdateInterval { get; set; }
public long updateTime { get; set; }
}
}

View File

@@ -389,9 +389,9 @@ namespace v2rayN.Mode
public QuicSettings quicSettings { get; set; }
/// <summary>
/// VLESS xtls
/// VLESS only
/// </summary>
public TlsSettings xtlsSettings { get; set; }
public TlsSettings realitySettings { get; set; }
/// <summary>
/// grpc
/// </summary>
@@ -404,24 +404,23 @@ namespace v2rayN.Mode
/// <summary>
/// 是否允许不安全连接(用于客户端)
/// </summary>
public bool allowInsecure { get; set; }
public bool? allowInsecure { get; set; }
/// <summary>
///
/// </summary>
public string serverName { get; set; }
public string? serverName { get; set; }
/// <summary>
///
/// </summary>
public List<string> alpn
{
get; set;
}
public List<string>? alpn { get; set; }
/// <summary>
/// "chrome" | "firefox" | "safari" | "randomized"
/// </summary>
public string fingerprint { get; set; }
public string? fingerprint { get; set; }
public bool? show { get; set; } = false;
public string? publicKey { get; set; }
public string? shortId { get; set; }
public string? spiderX { get; set; }
}

View File

@@ -367,11 +367,11 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Alias 的本地化字符串。
/// 查找类似 Automatic update interval(minutes) 的本地化字符串。
/// </summary>
public static string LvAlias {
public static string LvAutoUpdateInterval {
get {
return ResourceManager.GetString("LvAlias", resourceCulture);
return ResourceManager.GetString("LvAutoUpdateInterval", resourceCulture);
}
}
@@ -420,6 +420,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 More urls, separated by commas 的本地化字符串。
/// </summary>
public static string LvMoreUrl {
get {
return ResourceManager.GetString("LvMoreUrl", resourceCulture);
}
}
/// <summary>
/// 查找类似 Port 的本地化字符串。
/// </summary>
@@ -474,15 +483,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Test Results 的本地化字符串。
/// </summary>
public static string LvTestResults {
get {
return ResourceManager.GetString("LvTestResults", resourceCulture);
}
}
/// <summary>
/// 查找类似 Speed(M/s) 的本地化字符串。
/// </summary>
@@ -564,15 +564,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Medium 的本地化字符串。
/// </summary>
public static string MediumFresh {
get {
return ResourceManager.GetString("MediumFresh", resourceCulture);
}
}
/// <summary>
/// 查找类似 Add a custom configuration server 的本地化字符串。
/// </summary>
@@ -816,6 +807,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Move up and down 的本地化字符串。
/// </summary>
public static string menuMoveTo {
get {
return ResourceManager.GetString("menuMoveTo", resourceCulture);
}
}
/// <summary>
/// 查找类似 Move to group 的本地化字符串。
/// </summary>
@@ -924,6 +924,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Reboot as administrator 的本地化字符串。
/// </summary>
public static string menuRebootAsAdmin {
get {
return ResourceManager.GetString("menuRebootAsAdmin", resourceCulture);
}
}
/// <summary>
/// 查找类似 Reload 的本地化字符串。
/// </summary>
@@ -1375,7 +1384,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Please fill in the address (Url) 的本地化字符串。
/// 查找类似 Please fill in the Url 的本地化字符串。
/// </summary>
public static string MsgNeedUrl {
get {
@@ -1392,24 +1401,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 PAC update failed 的本地化字符串。
/// </summary>
public static string MsgPACUpdateFailed {
get {
return ResourceManager.GetString("MsgPACUpdateFailed", resourceCulture);
}
}
/// <summary>
/// 查找类似 PAC update succeeded 的本地化字符串。
/// </summary>
public static string MsgPACUpdateSuccessfully {
get {
return ResourceManager.GetString("MsgPACUpdateSuccessfully", resourceCulture);
}
}
/// <summary>
/// 查找类似 Resolve {0} successfully 的本地化字符串。
/// </summary>
@@ -1420,7 +1411,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Servers Filter 的本地化字符串。
/// 查找类似 Servers Filter, press Enter to execute 的本地化字符串。
/// </summary>
public static string MsgServerTitle {
get {
@@ -1429,11 +1420,11 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Simplify PAC Success 的本地化字符串。
/// 查找类似 Updates are not enabled, skip this subscription 的本地化字符串。
/// </summary>
public static string MsgSimplifyPAC {
public static string MsgSkipSubscriptionUpdate {
get {
return ResourceManager.GetString("MsgSimplifyPAC", resourceCulture);
return ResourceManager.GetString("MsgSkipSubscriptionUpdate", resourceCulture);
}
}
@@ -1455,15 +1446,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Start updating PAC... 的本地化字符串。
/// </summary>
public static string MsgStartUpdatingPAC {
get {
return ResourceManager.GetString("MsgStartUpdatingPAC", resourceCulture);
}
}
/// <summary>
/// 查找类似 Invalid subscription content 的本地化字符串。
/// </summary>
@@ -1518,24 +1500,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 This feature relies on the Http global proxy, please set it correctly first. 的本地化字符串。
/// </summary>
public static string NeedHttpGlobalProxy {
get {
return ResourceManager.GetString("NeedHttpGlobalProxy", resourceCulture);
}
}
/// <summary>
/// 查找类似 Normal use of this version requires .NET Framework 4.8 的本地化字符串。
/// </summary>
public static string NetFrameworkRequirementsTip {
get {
return ResourceManager.GetString("NetFrameworkRequirementsTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Non-VMess or ss protocol 的本地化字符串。
/// </summary>
@@ -1644,15 +1608,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Fast 的本地化字符串。
/// </summary>
public static string QuickFresh {
get {
return ResourceManager.GetString("QuickFresh", resourceCulture);
}
}
/// <summary>
/// 查找类似 Global hotkey {0} registered failed, reason {1} 的本地化字符串。
/// </summary>
@@ -1735,20 +1690,11 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Slow 的本地化字符串。
/// 查找类似 {0}:{1}/s↑ | {2}/s↓ 的本地化字符串。
/// </summary>
public static string SlowFresh {
public static string SpeedDisplayText {
get {
return ResourceManager.GetString("SlowFresh", resourceCulture);
}
}
/// <summary>
/// 查找类似 Note: This feature relies on the Http global proxy. Please manually adjust the Http global proxy and active node after testing. 的本地化字符串。
/// </summary>
public static string SpeedServerTips {
get {
return ResourceManager.GetString("SpeedServerTips", resourceCulture);
return ResourceManager.GetString("SpeedDisplayText", resourceCulture);
}
}
@@ -1780,11 +1726,11 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 PAC failed to start. Please run this program as Administrator. 的本地化字符串。
/// 查找类似 Waiting for testing 的本地化字符串。
/// </summary>
public static string StartPacFailed {
public static string SpeedtestingWait {
get {
return ResourceManager.GetString("StartPacFailed", resourceCulture);
return ResourceManager.GetString("SpeedtestingWait", resourceCulture);
}
}
@@ -2158,6 +2104,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 PublicKey 的本地化字符串。
/// </summary>
public static string TbPublicKey {
get {
return ResourceManager.GetString("TbPublicKey", resourceCulture);
}
}
/// <summary>
/// 查找类似 Alias (remarks) 的本地化字符串。
/// </summary>
@@ -2311,24 +2266,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Automatic latency test interval (minutes) 的本地化字符串。
/// </summary>
public static string TbSettingsAutoTest {
get {
return ResourceManager.GetString("TbSettingsAutoTest", resourceCulture);
}
}
/// <summary>
/// 查找类似 Automatic update interval of subscriptions (hours) 的本地化字符串。
/// </summary>
public static string TbSettingsAutoUpdate {
get {
return ResourceManager.GetString("TbSettingsAutoUpdate", resourceCulture);
}
}
/// <summary>
/// 查找类似 Automatic update interval of and Geo (hours) 的本地化字符串。
/// </summary>
@@ -2491,6 +2428,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Enable hardware acceleration(Require restart) 的本地化字符串。
/// </summary>
public static string TbSettingsEnableHWA {
get {
return ResourceManager.GetString("TbSettingsEnableHWA", resourceCulture);
}
}
/// <summary>
/// 查找类似 Exception 的本地化字符串。
/// </summary>
@@ -2536,15 +2482,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Enable IPv6 的本地化字符串。
/// </summary>
public static string TbSettingsIpv6 {
get {
return ResourceManager.GetString("TbSettingsIpv6", resourceCulture);
}
}
/// <summary>
/// 查找类似 Keep older when deduplication 的本地化字符串。
/// </summary>
@@ -2564,7 +2501,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 Record local logs 的本地化字符串。
/// 查找类似 Enable Log 的本地化字符串。
/// </summary>
public static string TbSettingsLogEnabled {
get {
@@ -2572,6 +2509,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Enable logging to file 的本地化字符串。
/// </summary>
public static string TbSettingsLogEnabledToFile {
get {
return ResourceManager.GetString("TbSettingsLogEnabledToFile", resourceCulture);
}
}
/// <summary>
/// 查找类似 Log Level 的本地化字符串。
/// </summary>
@@ -2608,15 +2554,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Pac listen port 的本地化字符串。
/// </summary>
public static string TbSettingsPacListenPort {
get {
return ResourceManager.GetString("TbSettingsPacListenPort", resourceCulture);
}
}
/// <summary>
/// 查找类似 Auth pass 的本地化字符串。
/// </summary>
@@ -2644,15 +2581,6 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 After modifying the following parameters, click Save to take effect 的本地化字符串。
/// </summary>
public static string TbSettingsSaveTip {
get {
return ResourceManager.GetString("TbSettingsSaveTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
/// </summary>
@@ -2833,6 +2761,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 DNS object, e.g. {&quot;servers&quot;:[]} 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeDNS {
get {
return ResourceManager.GetString("TbSettingsTunModeDNS", resourceCulture);
}
}
/// <summary>
/// 查找类似 Proxy IP CIDR, separated by commas (,) 的本地化字符串。
/// </summary>
@@ -2878,6 +2815,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 ShortId 的本地化字符串。
/// </summary>
public static string TbShortId {
get {
return ResourceManager.GetString("TbShortId", resourceCulture);
}
}
/// <summary>
/// 查找类似 SNI 的本地化字符串。
/// </summary>
@@ -2887,6 +2833,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 SpiderX 的本地化字符串。
/// </summary>
public static string TbSpiderX {
get {
return ResourceManager.GetString("TbSpiderX", resourceCulture);
}
}
/// <summary>
/// 查找类似 TLS 的本地化字符串。
/// </summary>
@@ -2932,6 +2887,15 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Please turn off when there is an abnormal disconnection 的本地化字符串。
/// </summary>
public static string TipDisplayLog {
get {
return ResourceManager.GetString("TipDisplayLog", resourceCulture);
}
}
/// <summary>
/// 查找类似 *Default value tcp 的本地化字符串。
/// </summary>
@@ -3068,7 +3032,7 @@ namespace v2rayN.Resx {
}
/// <summary>
/// 查找类似 *QUIC securty 的本地化字符串。
/// 查找类似 *QUIC security 的本地化字符串。
/// </summary>
public static string TransportRequestHostTip4 {
get {

View File

@@ -195,9 +195,6 @@
<data name="LvAddress" xml:space="preserve">
<value>آدرس</value>
</data>
<data name="LvAlias" xml:space="preserve">
<value>Alias</value>
</data>
<data name="LvEncryptionMethod" xml:space="preserve">
<value>امنیت</value>
</data>
@@ -210,9 +207,6 @@
<data name="LvSubscription" xml:space="preserve">
<value>گروه فرعی</value>
</data>
<data name="LvTestResults" xml:space="preserve">
<value>نتایج تست</value>
</data>
<data name="LvTodayDownloadDataAmount" xml:space="preserve">
<value> ترافیک دانلود امروز</value>
</data>
@@ -228,9 +222,6 @@
<data name="LvTransportProtocol" xml:space="preserve">
<value>جابجایی</value>
</data>
<data name="MediumFresh" xml:space="preserve">
<value>متوسط</value>
</data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>محتوای اشتراک اصلی را پاک کنید</value>
</data>
@@ -246,27 +237,15 @@
<data name="MsgNoValidSubscription" xml:space="preserve">
<value>هیچ اشتراک معتبری تنظیم نشده است</value>
</data>
<data name="MsgPACUpdateFailed" xml:space="preserve">
<value>به روز رسانی PAC ناموفق بود</value>
</data>
<data name="MsgPACUpdateSuccessfully" xml:space="preserve">
<value>به روز رسانی PAC با موفقیت انجام شد</value>
</data>
<data name="MsgParsingSuccessfully" xml:space="preserve">
<value>Resolve {0} successfully</value>
</data>
<data name="MsgSimplifyPAC" xml:space="preserve">
<value>Simplify PAC Success</value>
</data>
<data name="MsgStartGettingSubscriptions" xml:space="preserve">
<value>شروع به دریافت اشتراک شد</value>
</data>
<data name="MsgStartUpdating" xml:space="preserve">
<value>شروع بروزرسانی {0}...</value>
</data>
<data name="MsgStartUpdatingPAC" xml:space="preserve">
<value>شروع بروزرسانی PAC...</value>
</data>
<data name="MsgSubscriptionDecodingFailed" xml:space="preserve">
<value>محتوای اشتراک نامعتبر است</value>
</data>
@@ -285,9 +264,6 @@
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
<value>هسته با موفقیت بروزرسانی شد! راه اندازی مجدد سرویس...</value>
</data>
<data name="NeedHttpGlobalProxy" xml:space="preserve">
<value> This feature relies on the Http global proxy, please set it correctly first.</value>
</data>
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Non-VMess or ss protocol</value>
</data>
@@ -315,9 +291,6 @@
<data name="PleaseSelectServer" xml:space="preserve">
<value>لطفا ابتدا سرور را انتخاب کنید</value>
</data>
<data name="QuickFresh" xml:space="preserve">
<value>سریع</value>
</data>
<data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>Servers deduplication completed. Old: {0}, New: {1}.</value>
</data>
@@ -330,15 +303,6 @@
<data name="SaveServerConfigurationIn" xml:space="preserve">
<value>The server configuration file is saved at: {0}</value>
</data>
<data name="SlowFresh" xml:space="preserve">
<value>آهسته. تدریجی</value>
</data>
<data name="SpeedServerTips" xml:space="preserve">
<value>توجه: این ویژگی به پروکسی جهانی Http متکی است. لطفاً پس از آزمایش، پراکسی جهانی Http و گره فعال را به صورت دستی تنظیم کنید.</value>
</data>
<data name="StartPacFailed" xml:space="preserve">
<value>PAC شروع نشد. لطفا این برنامه را به عنوان Administrator اجرا کنید.</value>
</data>
<data name="StartService" xml:space="preserve">
<value>Start service ({0})...</value>
</data>
@@ -472,9 +436,6 @@
<data name="MsgServerTitle" xml:space="preserve">
<value>فیلتر سرورها</value>
</data>
<data name="NetFrameworkRequirementsTip" xml:space="preserve">
<value>استفاده معمولی از این نسخه به .NET Framework 4.8 نیاز دارد</value>
</data>
<data name="menuCheckUpdate" xml:space="preserve">
<value>بررسی بروزرسانی</value>
</data>
@@ -763,12 +724,6 @@
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>Auto hide startup</value>
</data>
<data name="TbSettingsAutoTest" xml:space="preserve">
<value>فاصله تست تأخیر خودکار (دقیقه)</value>
</data>
<data name="TbSettingsAutoUpdate" xml:space="preserve">
<value>فاصله به روز رسانی خودکار اشتراک ها (ساعت)</value>
</data>
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>فاصله به روز رسانی خودکار و Geo (ساعت)</value>
</data>
@@ -808,9 +763,6 @@
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>هنگام به‌روزرسانی هسته، فایل‌های Geo را نادیده بگیرید</value>
</data>
<data name="TbSettingsIpv6" xml:space="preserve">
<value>IPv6 را فعال کنید</value>
</data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>Keep older when deduplication</value>
</data>
@@ -826,18 +778,12 @@
<data name="TbSettingsN" xml:space="preserve">
<value>تنظیمات v2rayN</value>
</data>
<data name="TbSettingsPacListenPort" xml:space="preserve">
<value>Pac پورت درحال شنود</value>
</data>
<data name="TbSettingsPass" xml:space="preserve">
<value>Auth pass</value>
</data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>سفارشی DNS (multiple, separated by commas (,))</value>
</data>
<data name="TbSettingsSaveTip" xml:space="preserve">
<value>After modifying the following parameters, click Save to take effect</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve">
<value>Set Win10 UWP Loopback</value>
</data>
@@ -1066,4 +1012,7 @@
<data name="TbSettingsDefUserAgentTips" xml:space="preserve">
<value>This parameter is valid only for tcp/http and ws</value>
</data>
<data name="TbSettingsEnableHWA" xml:space="preserve">
<value>فعال‌سازی شتاب‌دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد)</value>
</data>
</root>

View File

@@ -195,9 +195,6 @@
<data name="LvAddress" xml:space="preserve">
<value>Address</value>
</data>
<data name="LvAlias" xml:space="preserve">
<value>Alias</value>
</data>
<data name="LvEncryptionMethod" xml:space="preserve">
<value>Security</value>
</data>
@@ -210,9 +207,6 @@
<data name="LvSubscription" xml:space="preserve">
<value>Subs group</value>
</data>
<data name="LvTestResults" xml:space="preserve">
<value>Test Results</value>
</data>
<data name="LvTodayDownloadDataAmount" xml:space="preserve">
<value>Download traffic today</value>
</data>
@@ -228,9 +222,6 @@
<data name="LvTransportProtocol" xml:space="preserve">
<value>Transport</value>
</data>
<data name="MediumFresh" xml:space="preserve">
<value>Medium</value>
</data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>Clear original subscription content</value>
</data>
@@ -246,27 +237,15 @@
<data name="MsgNoValidSubscription" xml:space="preserve">
<value>No valid subscriptions set</value>
</data>
<data name="MsgPACUpdateFailed" xml:space="preserve">
<value>PAC update failed</value>
</data>
<data name="MsgPACUpdateSuccessfully" xml:space="preserve">
<value>PAC update succeeded</value>
</data>
<data name="MsgParsingSuccessfully" xml:space="preserve">
<value>Resolve {0} successfully</value>
</data>
<data name="MsgSimplifyPAC" xml:space="preserve">
<value>Simplify PAC Success</value>
</data>
<data name="MsgStartGettingSubscriptions" xml:space="preserve">
<value>Start getting subscriptions</value>
</data>
<data name="MsgStartUpdating" xml:space="preserve">
<value>Start updating {0}...</value>
</data>
<data name="MsgStartUpdatingPAC" xml:space="preserve">
<value>Start updating PAC...</value>
</data>
<data name="MsgSubscriptionDecodingFailed" xml:space="preserve">
<value>Invalid subscription content</value>
</data>
@@ -285,9 +264,6 @@
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
<value>Update Core successfully! Restarting service...</value>
</data>
<data name="NeedHttpGlobalProxy" xml:space="preserve">
<value> This feature relies on the Http global proxy, please set it correctly first.</value>
</data>
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Non-VMess or ss protocol</value>
</data>
@@ -315,9 +291,6 @@
<data name="PleaseSelectServer" xml:space="preserve">
<value>Please select the server first</value>
</data>
<data name="QuickFresh" xml:space="preserve">
<value>Fast</value>
</data>
<data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>Servers deduplication completed. Old: {0}, New: {1}.</value>
</data>
@@ -330,15 +303,6 @@
<data name="SaveServerConfigurationIn" xml:space="preserve">
<value>The server configuration file is saved at: {0}</value>
</data>
<data name="SlowFresh" xml:space="preserve">
<value>Slow</value>
</data>
<data name="SpeedServerTips" xml:space="preserve">
<value>Note: This feature relies on the Http global proxy. Please manually adjust the Http global proxy and active node after testing.</value>
</data>
<data name="StartPacFailed" xml:space="preserve">
<value>PAC failed to start. Please run this program as Administrator.</value>
</data>
<data name="StartService" xml:space="preserve">
<value>Start service ({0})...</value>
</data>
@@ -380,7 +344,7 @@
<value>Count</value>
</data>
<data name="MsgNeedUrl" xml:space="preserve">
<value>Please fill in the address (Url)</value>
<value>Please fill in the Url</value>
</data>
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value>
@@ -419,7 +383,7 @@
<value>*h2 host Separated by commas (,)</value>
</data>
<data name="TransportRequestHostTip4" xml:space="preserve">
<value>*QUIC securty</value>
<value>*QUIC security</value>
</data>
<data name="TransportHeaderTypeTip1" xml:space="preserve">
<value>*tcp camouflage type</value>
@@ -470,10 +434,7 @@
<value>Local</value>
</data>
<data name="MsgServerTitle" xml:space="preserve">
<value>Servers Filter</value>
</data>
<data name="NetFrameworkRequirementsTip" xml:space="preserve">
<value>Normal use of this version requires .NET Framework 4.8</value>
<value>Servers Filter, press Enter to execute</value>
</data>
<data name="menuCheckUpdate" xml:space="preserve">
<value>Check Update</value>
@@ -763,12 +724,6 @@
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>Auto hide startup</value>
</data>
<data name="TbSettingsAutoTest" xml:space="preserve">
<value>Automatic latency test interval (minutes)</value>
</data>
<data name="TbSettingsAutoUpdate" xml:space="preserve">
<value>Automatic update interval of subscriptions (hours)</value>
</data>
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval of and Geo (hours)</value>
</data>
@@ -808,14 +763,11 @@
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>Ignore Geo files when updating core</value>
</data>
<data name="TbSettingsIpv6" xml:space="preserve">
<value>Enable IPv6</value>
</data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>Keep older when deduplication</value>
</data>
<data name="TbSettingsLogEnabled" xml:space="preserve">
<value>Record local logs</value>
<value>Enable Log</value>
</data>
<data name="TbSettingsLogLevel" xml:space="preserve">
<value>Log Level</value>
@@ -826,18 +778,12 @@
<data name="TbSettingsN" xml:space="preserve">
<value>v2rayN settings</value>
</data>
<data name="TbSettingsPacListenPort" xml:space="preserve">
<value>Pac listen port</value>
</data>
<data name="TbSettingsPass" xml:space="preserve">
<value>Auth pass</value>
</data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>Custom DNS (multiple, separated by commas (,))</value>
</data>
<data name="TbSettingsSaveTip" xml:space="preserve">
<value>After modifying the following parameters, click Save to take effect</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve">
<value>Set Win10 UWP Loopback</value>
</data>
@@ -1126,4 +1072,46 @@
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest Url</value>
</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>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbSettingsEnableHWA" xml:space="preserve">
<value>Enable hardware acceleration(Require restart)</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>Updates are not enabled, skip this subscription</value>
</data>
<data name="menuRebootAsAdmin" xml:space="preserve">
<value>Reboot as administrator</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More urls, separated by commas</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0}:{1}/s↑ | {2}/s↓</value>
</data>
<data name="LvAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval(minutes)</value>
</data>
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>Enable logging to file</value>
</data>
</root>

File diff suppressed because it is too large Load Diff

View File

@@ -130,7 +130,7 @@
<value>配置格式不正确</value>
</data>
<data name="CustomServerTips" xml:space="preserve">
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value>
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>下载开始...</value>
@@ -148,7 +148,7 @@
<value>生成默认配置文件失败</value>
</data>
<data name="FailedGetDefaultConfiguration" xml:space="preserve">
<value>取默认配置失败</value>
<value>取默认配置失败</value>
</data>
<data name="FailedImportedCustomServer" xml:space="preserve">
<value>导入自定义配置服务器失败</value>
@@ -195,9 +195,6 @@
<data name="LvAddress" xml:space="preserve">
<value>地址</value>
</data>
<data name="LvAlias" xml:space="preserve">
<value>别名</value>
</data>
<data name="LvEncryptionMethod" xml:space="preserve">
<value>加密方式</value>
</data>
@@ -210,9 +207,6 @@
<data name="LvSubscription" xml:space="preserve">
<value>订阅分组</value>
</data>
<data name="LvTestResults" xml:space="preserve">
<value>测试结果</value>
</data>
<data name="LvTodayDownloadDataAmount" xml:space="preserve">
<value>今日下载</value>
</data>
@@ -228,9 +222,6 @@
<data name="LvTransportProtocol" xml:space="preserve">
<value>传输协议</value>
</data>
<data name="MediumFresh" xml:space="preserve">
<value>中等</value>
</data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>清除原订阅内容</value>
</data>
@@ -246,27 +237,15 @@
<data name="MsgNoValidSubscription" xml:space="preserve">
<value>未设置有效的订阅</value>
</data>
<data name="MsgPACUpdateFailed" xml:space="preserve">
<value>PAC更新失败</value>
</data>
<data name="MsgPACUpdateSuccessfully" xml:space="preserve">
<value>PAC更新成功</value>
</data>
<data name="MsgParsingSuccessfully" xml:space="preserve">
<value>解析{0}成功</value>
</data>
<data name="MsgSimplifyPAC" xml:space="preserve">
<value>简化PAC成功</value>
</data>
<data name="MsgStartGettingSubscriptions" xml:space="preserve">
<value>开始获取订阅内容</value>
</data>
<data name="MsgStartUpdating" xml:space="preserve">
<value>开始更新 {0}...</value>
</data>
<data name="MsgStartUpdatingPAC" xml:space="preserve">
<value>开始更新 PAC...</value>
</data>
<data name="MsgSubscriptionDecodingFailed" xml:space="preserve">
<value>无效的订阅内容</value>
</data>
@@ -285,9 +264,6 @@
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
<value>更新Core成功正在重启服务...</value>
</data>
<data name="NeedHttpGlobalProxy" xml:space="preserve">
<value>此功能依赖Http全局代理,请先设置正确。</value>
</data>
<data name="NonvmessOrssProtocol" xml:space="preserve">
<value>非VMess或ss协议</value>
</data>
@@ -304,7 +280,7 @@
<value>操作失败,请检查重试</value>
</data>
<data name="PleaseFillRemarks" xml:space="preserve">
<value>请填写备注</value>
<value>请填写别名</value>
</data>
<data name="PleaseSelectEncryption" xml:space="preserve">
<value>请选择加密方式</value>
@@ -315,9 +291,6 @@
<data name="PleaseSelectServer" xml:space="preserve">
<value>请先选择服务器</value>
</data>
<data name="QuickFresh" xml:space="preserve">
<value>快</value>
</data>
<data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>服务器去重完成。原数量: {0},现数量: {1}</value>
</data>
@@ -330,15 +303,6 @@
<data name="SaveServerConfigurationIn" xml:space="preserve">
<value>服务端配置文件保存在:{0}</value>
</data>
<data name="SlowFresh" xml:space="preserve">
<value>慢</value>
</data>
<data name="SpeedServerTips" xml:space="preserve">
<value>注意此功能依赖Http全局代理!测试完成后,请手工调整Http全局代理和活动节点。</value>
</data>
<data name="StartPacFailed" xml:space="preserve">
<value>PAC服务启动失败,请用管理员启动</value>
</data>
<data name="StartService" xml:space="preserve">
<value>启动服务({0})...</value>
</data>
@@ -380,7 +344,7 @@
<value>数量</value>
</data>
<data name="MsgNeedUrl" xml:space="preserve">
<value>请填写地址(Url)</value>
<value>请填写Url</value>
</data>
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
<value>是否追加规则?选择是则追加,选择否则替换</value>
@@ -410,13 +374,13 @@
<value>*grpc serviceName</value>
</data>
<data name="TransportRequestHostTip1" xml:space="preserve">
<value>*http host中间逗号(,)隔</value>
<value>*http host中间逗号(,)隔</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中间逗号(,)隔</value>
<value>*h2 host中间逗号(,)隔</value>
</data>
<data name="TransportRequestHostTip4" xml:space="preserve">
<value>*QUIC 加密方式</value>
@@ -470,10 +434,7 @@
<value>本地</value>
</data>
<data name="MsgServerTitle" xml:space="preserve">
<value>服务器过滤器</value>
</data>
<data name="NetFrameworkRequirementsTip" xml:space="preserve">
<value>正常使用此版本需要.NET Framework 4.8,请更新后重启</value>
<value>服务器过滤器,按回车执行</value>
</data>
<data name="menuCheckUpdate" xml:space="preserve">
<value>检查更新</value>
@@ -710,7 +671,7 @@
<value>SNI</value>
</data>
<data name="TbStreamSecurity" xml:space="preserve">
<value>TLS</value>
<value>传输层安全(TLS)</value>
</data>
<data name="TipNetwork" xml:space="preserve">
<value>*默认tcp,选错会无法连接</value>
@@ -763,12 +724,6 @@
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>启动后隐藏窗口</value>
</data>
<data name="TbSettingsAutoTest" xml:space="preserve">
<value>自动延迟测试的间隔 (单位分钟)</value>
</data>
<data name="TbSettingsAutoUpdate" xml:space="preserve">
<value>自动更新订阅的间隔(单位小时)</value>
</data>
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>自动更新Geo文件的间隔(单位小时)</value>
</data>
@@ -808,14 +763,11 @@
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core时忽略Geo文件</value>
</data>
<data name="TbSettingsIpv6" xml:space="preserve">
<value>启用IPv6</value>
</data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>去重时保留序号较小的项</value>
</data>
<data name="TbSettingsLogEnabled" xml:space="preserve">
<value>记录本地日志(默认关闭)</value>
<value>启用日志</value>
</data>
<data name="TbSettingsLogLevel" xml:space="preserve">
<value>日志等级</value>
@@ -826,17 +778,11 @@
<data name="TbSettingsN" xml:space="preserve">
<value>v2rayN 设置</value>
</data>
<data name="TbSettingsPacListenPort" xml:space="preserve">
<value>Pac监听端口号</value>
</data>
<data name="TbSettingsPass" xml:space="preserve">
<value>认证密码</value>
</data>
<data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>自定义DNS(可多个,用逗号(,)隔)</value>
</data>
<data name="TbSettingsSaveTip" xml:space="preserve">
<value>修改以下参数后,点击保存才生效</value>
<value>自定义DNS(可多个,用逗号(,)隔)</value>
</data>
<data name="TbSettingsSetUWP" xml:space="preserve">
<value>解除Win10 UWP应用回环代理限制</value>
@@ -905,7 +851,7 @@
<value>路由</value>
</data>
<data name="NotRunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value>
<value>以管理员身份运行</value>
</data>
<data name="RunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value>
@@ -1126,4 +1072,43 @@
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>测速文件地址</value>
</data>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS对象例如 {"servers":[]}</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>移至上下</value>
</data>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbSettingsEnableHWA" xml:space="preserve">
<value>启用硬件加速(需重启)</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>等待测试中...</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>当有异常断流时请关闭</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>未启用更新,跳过此订阅</value>
</data>
<data name="menuRebootAsAdmin" xml:space="preserve">
<value>以管理员身份重启</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>更多地址(url),用逗号(,)分隔</value>
</data>
<data name="LvAutoUpdateInterval" xml:space="preserve">
<value>自动更新间隔(分钟)</value>
</data>
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>启用日志存到文件</value>
</data>
</root>

View File

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

View File

@@ -1,31 +1,11 @@
{
"log": {
"disabled": false,
"disabled": $log_disabled$,
"level": "debug",
$log_output$
"timestamp": true
},
"dns": {
"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"
},
"dns": $dns_object$ ,
"inbounds": [
{
"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
{
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
fs.Write(content, 0, content.Length);
File.WriteAllBytes(fileName, content);
return true;
}
catch (Exception ex)
@@ -25,20 +24,9 @@ namespace v2rayN.Tool
{
try
{
// Because the uncompressed size of the file is unknown,
// we are using an arbitrary buffer size.
byte[] buffer = new byte[4096];
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);
}
}
using FileStream fs = File.Create(fileName);
using GZipStream input = new(new MemoryStream(content), CompressionMode.Decompress, false);
input.CopyTo(fs);
}
catch (Exception ex)
{
@@ -55,24 +43,21 @@ namespace v2rayN.Tool
{
try
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader sr = new StreamReader(fs, encoding))
{
using FileStream fs = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using StreamReader sr = new(fs, encoding);
return sr.ReadToEnd();
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
throw ex;
throw;
}
}
public static bool ZipExtractToFile(string fileName, string toPath, string ignoredName)
{
try
{
using (ZipArchive archive = ZipFile.OpenRead(fileName))
{
using ZipArchive archive = ZipFile.OpenRead(fileName);
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.Length == 0)
@@ -93,7 +78,6 @@ namespace v2rayN.Tool
}
}
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);

View File

@@ -16,12 +16,12 @@ namespace v2rayN
{
handle = CreateJobObject(IntPtr.Zero, null);
IntPtr extendedInfoPtr = IntPtr.Zero;
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
{
LimitFlags = 0x2000
};
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
{
BasicLimitInformation = info
};
@@ -100,7 +100,7 @@ namespace v2rayN
#region Interop
[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)]
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);

View File

@@ -9,14 +9,21 @@ namespace v2rayN.Tool
{
public static void Setup()
{
LoggingConfiguration config = new LoggingConfiguration();
FileTarget fileTarget = new FileTarget();
LoggingConfiguration config = new();
FileTarget fileTarget = new();
config.AddTarget("file", fileTarget);
fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget));
LogManager.Configuration = config;
}
public static void LoggingEnabled(bool enable)
{
if (!enable)
{
LogManager.SuspendLogging();
}
}
public static void ClearLogs()
{

View File

@@ -1,45 +1,22 @@
using System.Windows.Forms;
using System.Windows;
namespace v2rayN
{
class UI
{
private readonly static string caption = "v2rayN";
public static void Show(string msg)
{
MessageBox.Show(msg, "v2rayN", MessageBoxButtons.OK, MessageBoxIcon.Information);
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
}
public static void ShowWarning(string msg)
{
MessageBox.Show(msg, "v2rayN", MessageBoxButtons.OK, MessageBoxIcon.Warning);
MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK);
}
public static void ShowError(string msg)
public static MessageBoxResult ShowYesNo(string msg)
{
MessageBox.Show(msg, "v2rayN", MessageBoxButtons.OK, MessageBoxIcon.Error);
return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question);
}
public static DialogResult ShowYesNo(string msg)
{
return MessageBox.Show(msg, "v2rayN", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
}
//public static string GetResourseString(string key)
//{
// CultureInfo cultureInfo = null;
// try
// {
// string languageCode = this.LanguageCode;
// cultureInfo = new CultureInfo(languageCode);
// return Common.ResourceManager.GetString(key, cultureInfo);
// }
// catch (Exception)
// {
// //默认读取英文的多语言
// cultureInfo = new CultureInfo(MKey.kDefaultLanguageCode);
// return Common.ResourceManager.GetString(key, cultureInfo);
// }
//}
}
}

View File

@@ -18,7 +18,7 @@ using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Windows.Forms;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
@@ -48,12 +48,11 @@ namespace v2rayN
try
{
Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(res))
using (StreamReader reader = new StreamReader(stream))
{
using Stream? stream = assembly.GetManifestResourceStream(res);
ArgumentNullException.ThrowIfNull(stream);
using StreamReader reader = new(stream);
result = reader.ReadToEnd();
}
}
catch (Exception ex)
{
SaveLog(ex.Message, ex);
@@ -66,22 +65,18 @@ namespace v2rayN
/// 取得存储资源
/// </summary>
/// <returns></returns>
public static string LoadResource(string res)
public static string? LoadResource(string res)
{
string result = string.Empty;
try
{
using (StreamReader reader = new StreamReader(res))
{
result = reader.ReadToEnd();
}
if (!File.Exists(res)) return null;
return File.ReadAllText(res);
}
catch (Exception ex)
{
SaveLog(ex.Message, ex);
}
return result;
return null;
}
/// <summary>
@@ -90,7 +85,7 @@ namespace v2rayN
/// <typeparam name="T"></typeparam>
/// <param name="strJson"></param>
/// <returns></returns>
public static T FromJson<T>(string strJson)
public static T? FromJson<T>(string? strJson)
{
try
{
@@ -98,8 +93,7 @@ namespace v2rayN
{
return default;
}
T obj = JsonConvert.DeserializeObject<T>(strJson);
return obj;
return JsonConvert.DeserializeObject<T>(strJson);
}
catch
{
@@ -112,11 +106,15 @@ namespace v2rayN
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJson(Object obj, bool indented = true)
public static string ToJson(object? obj, bool indented = true)
{
string result = string.Empty;
try
{
if (obj == null)
{
return result;
}
if (indented)
{
result = JsonConvert.SerializeObject(obj,
@@ -141,13 +139,12 @@ namespace v2rayN
/// <param name="obj"></param>
/// <param name="filePath"></param>
/// <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;
try
{
using (StreamWriter file = File.CreateText(filePath))
{
using StreamWriter file = File.CreateText(filePath);
JsonSerializer serializer;
if (nullValue)
{
@@ -159,7 +156,6 @@ namespace v2rayN
}
serializer.Serialize(file, obj);
}
result = 0;
}
catch (Exception ex)
@@ -170,12 +166,11 @@ namespace v2rayN
return result;
}
public static JObject ParseJson(string strJson)
public static JObject? ParseJson(string strJson)
{
try
{
JObject obj = JObject.Parse(strJson);
return obj;
return JObject.Parse(strJson);
}
catch (Exception ex)
{
@@ -202,11 +197,11 @@ namespace v2rayN
}
if (wrap)
{
return string.Join("," + Environment.NewLine, lst.ToArray());
return string.Join("," + Environment.NewLine, lst);
}
else
{
return string.Join(",", lst.ToArray());
return string.Join(",", lst);
}
}
catch (Exception ex)
@@ -225,7 +220,7 @@ namespace v2rayN
try
{
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)
{
@@ -244,8 +239,9 @@ namespace v2rayN
try
{
str = str.Replace(Environment.NewLine, "");
List<string> list = new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries));
return list.OrderBy(x => x).ToList();
List<string> list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
list.Sort();
return list;
}
catch (Exception ex)
{
@@ -286,6 +282,8 @@ namespace v2rayN
.Replace(Environment.NewLine, "")
.Replace("\n", "")
.Replace("\r", "")
.Replace('_', '/')
.Replace('-', '+')
.Replace(" ", "");
if (plainText.Length % 4 > 0)
@@ -316,7 +314,7 @@ namespace v2rayN
}
catch (Exception ex)
{
SaveLog(ex.Message, ex);
//SaveLog(ex.Message, ex);
return 0;
}
}
@@ -328,7 +326,7 @@ namespace v2rayN
}
catch (Exception ex)
{
SaveLog(ex.Message, ex);
//SaveLog(ex.Message, ex);
return false;
}
}
@@ -337,11 +335,11 @@ namespace v2rayN
{
try
{
return (obj == null ? string.Empty : obj.ToString());
return obj?.ToString() ?? string.Empty;
}
catch (Exception ex)
{
SaveLog(ex.Message, ex);
//SaveLog(ex.Message, ex);
return string.Empty;
}
}
@@ -369,23 +367,22 @@ namespace v2rayN
if (GBs > 0)
{
// multi GB
/*ulong TBs = GBs / factor;
long TBs = GBs / factor;
if (TBs > 0)
{
// 你是魔鬼吗? 用这么多流量
result = TBs + GBs % factor / (factor + 0.0);
result = TBs + (GBs % factor / (factor + 0.0));
unit = "TB";
return;
}*/
result = GBs + MBs % factor / (factor + 0.0);
}
result = GBs + (MBs % factor / (factor + 0.0));
unit = "GB";
return;
}
result = MBs + KBs % factor / (factor + 0.0);
result = MBs + (KBs % factor / (factor + 0.0));
unit = "MB";
return;
}
result = KBs + amount % factor / (factor + 0.0);
result = KBs + (amount % factor / (factor + 0.0));
unit = "KB";
return;
}
@@ -414,10 +411,9 @@ namespace v2rayN
public static string GetMD5(string str)
{
var md5 = MD5.Create();
byte[] byteOld = Encoding.UTF8.GetBytes(str);
byte[] byteNew = md5.ComputeHash(byteOld);
StringBuilder sb = new StringBuilder();
byte[] byteNew = MD5.HashData(byteOld);
StringBuilder sb = new(32);
foreach (byte b in byteNew)
{
sb.Append(b.ToString("x2"));
@@ -432,6 +428,11 @@ namespace v2rayN
BitmapSizeOptions.FromEmptyOptions());
}
/// <summary>
/// idn to idc
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string GetPunycode(string url)
{
if (string.IsNullOrWhiteSpace(url))
@@ -440,7 +441,7 @@ namespace v2rayN
}
try
{
Uri uri = new Uri(url);
Uri uri = new(url);
if (uri.Host == uri.IdnHost)
{
return url;
@@ -456,6 +457,12 @@ namespace v2rayN
}
}
public static bool IsBase64String(string plainText)
{
var buffer = new Span<byte>(new byte[plainText.Length]);
return Convert.TryFromBase64String(plainText, buffer, out int _);
}
#endregion
@@ -491,7 +498,7 @@ namespace v2rayN
{
return true;
}
if (text.Equals("null"))
if (text == "null")
{
return true;
}
@@ -568,18 +575,14 @@ namespace v2rayN
public static bool IsIpv6(string ip)
{
IPAddress address;
if (IPAddress.TryParse(ip, out address))
if (IPAddress.TryParse(ip, out IPAddress? address))
{
switch (address.AddressFamily)
return address.AddressFamily switch
{
case AddressFamily.InterNetwork:
return false;
case AddressFamily.InterNetworkV6:
return true;
default:
return false;
}
AddressFamily.InterNetwork => false,
AddressFamily.InterNetworkV6 => true,
_ => false,
};
}
return false;
}
@@ -642,7 +645,7 @@ namespace v2rayN
string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, "");
string exePath = GetExePath();
if (value?.Equals(exePath) == true || value?.Equals($"\"{exePath}\"") == true)
if (value == exePath || value == $"\"{exePath}\"")
{
return true;
}
@@ -674,21 +677,21 @@ namespace v2rayN
/// <returns></returns>
public static string GetExePath()
{
return Application.ExecutablePath;
return Environment.ProcessPath;
}
public static string StartupPath()
{
return Application.StartupPath;
return AppDomain.CurrentDomain.BaseDirectory;
}
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
{
regKey = Registry.CurrentUser.OpenSubKey(path, false);
string value = regKey?.GetValue(name) as string;
string? value = regKey?.GetValue(name) as string;
if (IsNullOrEmpty(value))
{
return def;
@@ -711,7 +714,7 @@ namespace v2rayN
public static void RegWriteValue(string path, string name, object value)
{
RegistryKey regKey = null;
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.CreateSubKey(path);
@@ -743,15 +746,13 @@ namespace v2rayN
public static bool CheckForDotNetVersion(int release = 528040)
{
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 ? true : false;
return (int)ndpKey.GetValue("Release") >= release;
}
return false;
}
}
/// <summary>
/// Auto Start via TaskService
@@ -771,8 +772,7 @@ namespace v2rayN
string taskDescription = description;
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)
{
@@ -790,13 +790,12 @@ namespace v2rayN
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromMinutes(1) });
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
}
}
#endregion
@@ -904,16 +903,13 @@ namespace v2rayN
public static T DeepCopy<T>(T obj)
{
object retval;
using (MemoryStream ms = new MemoryStream())
{
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
//序列化成流
bf.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
//反序列化成对象
retval = bf.Deserialize(ms);
ms.Close();
}
return (T)retval;
}
@@ -921,15 +917,15 @@ namespace v2rayN
/// 获取剪贴板数
/// </summary>
/// <returns></returns>
public static string GetClipboardData()
public static string? GetClipboardData()
{
string strData = string.Empty;
string? strData = string.Empty;
try
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.UnicodeText))
{
strData = data.GetData(DataFormats.UnicodeText).ToString();
strData = data.GetData(DataFormats.UnicodeText)?.ToString();
}
return strData;
}
@@ -1008,7 +1004,7 @@ namespace v2rayN
return fileName;
}
public static IPAddress GetDefaultGateway()
public static IPAddress? GetDefaultGateway()
{
return NetworkInterface
.GetAllNetworkInterfaces()
@@ -1071,14 +1067,11 @@ namespace v2rayN
public static string UnGzip(byte[] buf)
{
MemoryStream sb = new MemoryStream();
using (GZipStream input = new GZipStream(new MemoryStream(buf),
CompressionMode.Decompress,
false))
{
using MemoryStream sb = new();
using GZipStream input = new(new MemoryStream(buf), CompressionMode.Decompress, false);
input.CopyTo(sb);
}
return Encoding.UTF8.GetString(sb.ToArray());
sb.Position = 0;
return new StreamReader(sb, Encoding.UTF8).ReadToEnd();
}
public static string GetBackupPath(string filename)
@@ -1168,52 +1161,55 @@ namespace v2rayN
#region Log
public static void SaveLog(string strContent)
{
if (LogManager.IsLoggingEnabled())
{
var logger = LogManager.GetLogger("Log1");
logger.Info(strContent);
}
}
public static void SaveLog(string strTitle, Exception ex)
{
if (LogManager.IsLoggingEnabled())
{
var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace);
if (ex != null && ex.InnerException != null)
if (ex?.InnerException != null)
{
logger.Error(ex.InnerException);
}
}
}
#endregion
#region scan screen
public static string ScanScreen()
public static string ScanScreen(float dpiX, float dpiY)
{
try
{
foreach (Screen screen in Screen.AllScreens)
{
using (Bitmap fullImage = new Bitmap(screen.Bounds.Width,
screen.Bounds.Height))
{
var left = (int)(SystemParameters.WorkArea.Left);
var top = (int)(SystemParameters.WorkArea.Top);
var width = (int)(SystemParameters.WorkArea.Width / dpiX);
var height = (int)(SystemParameters.WorkArea.Height / dpiY);
using Bitmap fullImage = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(fullImage))
{
g.CopyFromScreen(screen.Bounds.X,
screen.Bounds.Y,
0, 0,
fullImage.Size,
CopyPixelOperation.SourceCopy);
g.CopyFromScreen(left, top, 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 Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
Rectangle cropRect = new(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new(width, height);
double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width;
double imageScale = (double)width / (double)cropRect.Width;
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
@@ -1221,9 +1217,9 @@ namespace v2rayN
GraphicsUnit.Pixel);
}
BitmapLuminanceSource source = new BitmapLuminanceSource(target);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
BitmapLuminanceSource source = new(target);
BinaryBitmap bitmap = new(new HybridBinarizer(source));
QRCodeReader reader = new();
Result result = reader.decode(bitmap);
if (result != null)
{
@@ -1232,8 +1228,6 @@ namespace v2rayN
}
}
}
}
}
catch (Exception ex)
{
SaveLog(ex.Message, ex);
@@ -1241,6 +1235,14 @@ namespace v2rayN
return string.Empty;
}
public static Tuple<float, float> GetDpiXY(Window window)
{
IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle();
Graphics g = Graphics.FromHwnd(hWnd);
return new(96 / g.DpiX, 96 / g.DpiY);
}
#endregion

View File

@@ -1,3 +1,4 @@
using Microsoft.Win32;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using ReactiveUI.Validation.Helpers;
@@ -5,7 +6,6 @@ using Splat;
using System.IO;
using System.Reactive;
using System.Windows;
using System.Windows.Forms;
using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
@@ -106,12 +106,12 @@ namespace v2rayN.ViewModels
{
UI.Show(ResUI.CustomServerTips);
OpenFileDialog fileDialog = new OpenFileDialog
OpenFileDialog fileDialog = new()
{
Multiselect = false,
Filter = "Config|*.json|YAML|*.yaml;*.yml|All|*.*"
};
if (fileDialog.ShowDialog() != DialogResult.OK)
if (fileDialog.ShowDialog() != true)
{
return;
}
@@ -121,10 +121,7 @@ namespace v2rayN.ViewModels
return;
}
var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId);
if (item is null)
{
item = SelectedSource;
}
item ??= SelectedSource;
item.address = fileName;
if (ConfigHandler.AddCustomServer(ref _config, item, false) == 0)
{

View File

@@ -118,6 +118,10 @@ namespace v2rayN.ViewModels
item.allowInsecure = SelectedSource.allowInsecure;
item.fingerprint = SelectedSource.fingerprint;
item.alpn = SelectedSource.alpn;
item.publicKey = SelectedSource.publicKey;
item.shortId = SelectedSource.shortId;
item.spiderX = SelectedSource.spiderX;
}
int ret = -1;

View File

@@ -3,17 +3,17 @@ using DynamicData.Binding;
using MaterialDesignColors;
using MaterialDesignColors.ColorManipulation;
using MaterialDesignThemes.Wpf;
using NHotkey;
using Microsoft.Win32;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using v2rayN.Base;
using v2rayN.Handler;
@@ -21,7 +21,6 @@ using v2rayN.Mode;
using v2rayN.Resx;
using v2rayN.Tool;
using v2rayN.Views;
using Application = System.Windows.Application;
namespace v2rayN.ViewModels
@@ -37,9 +36,9 @@ namespace v2rayN.ViewModels
private string _serverFilter = string.Empty;
private static Config _config;
private NoticeHandler? _noticeHandler;
private readonly PaletteHelper _paletteHelper = new PaletteHelper();
private Dictionary<int, bool> _dicHeaderSort = new();
private Action<string> _updateView;
private readonly PaletteHelper _paletteHelper = new();
private Dictionary<string, bool> _dicHeaderSort = new();
private Action<EViewAction> _updateView;
#endregion
@@ -70,6 +69,8 @@ namespace v2rayN.ViewModels
public ComboItem SelectedServer { get; set; }
[Reactive]
public string ServerFilter { get; set; }
[Reactive]
public bool BlServers { get; set; }
#endregion
#region Menu
@@ -121,6 +122,7 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> OptionSettingCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingSettingCmd { get; }
public ReactiveCommand<Unit, Unit> GlobalHotkeySettingCmd { get; }
public ReactiveCommand<Unit, Unit> RebootAsAdminCmd { get; }
public ReactiveCommand<Unit, Unit> ClearServerStatisticsCmd { get; }
public ReactiveCommand<Unit, Unit> ImportOldGuiConfigCmd { get; }
@@ -131,6 +133,7 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> CheckUpdateXrayCoreCmd { get; }
public ReactiveCommand<Unit, Unit> CheckUpdateClashCoreCmd { get; }
public ReactiveCommand<Unit, Unit> CheckUpdateClashMetaCoreCmd { get; }
public ReactiveCommand<Unit, Unit> CheckUpdateSingBoxCoreCmd { get; }
public ReactiveCommand<Unit, Unit> CheckUpdateGeoCmd { get; }
@@ -175,6 +178,8 @@ namespace v2rayN.ViewModels
[Reactive]
public string RunningServerDisplay { get; set; }
[Reactive]
public string RunningServerToolTipText { get; set; }
[Reactive]
public string RunningInfoDisplay { get; set; }
[Reactive]
public string SpeedProxyDisplay { get; set; }
@@ -198,7 +203,7 @@ namespace v2rayN.ViewModels
#region Init
public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue, Action<string> updateView)
public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue, Action<EViewAction> updateView)
{
_updateView = updateView;
ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
@@ -218,10 +223,11 @@ namespace v2rayN.ViewModels
{
EnableTun = true;
}
_subId = _config.subIndexId;
//RefreshServers();
InitSubscriptionView();
RefreshRoutingsMenu();
RefreshServers();
var canEditRemove = this.WhenAnyValue(
x => x.SelectedProfile,
@@ -254,7 +260,7 @@ namespace v2rayN.ViewModels
SystemProxySelected = (int)_config.sysProxyType;
this.WhenAnyValue(
x => x.SystemProxySelected,
y => y != null && y >= 0)
y => y >= 0)
.Subscribe(c => DoSystemProxySelected(c));
this.WhenAnyValue(
@@ -365,7 +371,7 @@ namespace v2rayN.ViewModels
}, canEditRemove);
SortServerResultCmd = ReactiveCommand.Create(() =>
{
SortServer((int)EServerColName.delay);
SortServer(EServerColName.delayVal.ToString());
});
//servers export
Export2ClientConfigCmd = ReactiveCommand.Create(() =>
@@ -428,6 +434,10 @@ namespace v2rayN.ViewModels
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
}
});
RebootAsAdminCmd = ReactiveCommand.Create(() =>
{
RebootAsAdmin();
});
ClearServerStatisticsCmd = ReactiveCommand.Create(() =>
{
_statistics?.ClearAllServerStatistics();
@@ -463,6 +473,10 @@ namespace v2rayN.ViewModels
{
CheckUpdateCore(ECoreType.clash_meta);
});
CheckUpdateSingBoxCoreCmd = ReactiveCommand.Create(() =>
{
CheckUpdateCore(ECoreType.sing_box);
});
CheckUpdateGeoCmd = ReactiveCommand.Create(() =>
{
CheckUpdateGeo();
@@ -532,16 +546,20 @@ namespace v2rayN.ViewModels
{
_noticeHandler?.SendMessage(msg);
}
private async void UpdateTaskHandler(bool success, string msg)
private void UpdateTaskHandler(bool success, string msg)
{
_noticeHandler?.SendMessage(msg);
if (success)
{
var indexIdOld = _config.indexId;
RefreshServers();
if (indexIdOld != _config.indexId)
{
Reload();
}
if (_config.uiItem.enableAutoAdjustMainLvColWidth)
{
_updateView("AdjustMainLvColWidth");
_updateView(EViewAction.AdjustMainLvColWidth);
}
}
}
@@ -555,8 +573,9 @@ namespace v2rayN.ViewModels
{
return;
}
SpeedProxyDisplay = string.Format("{0}:{1}/s<><73> | {2}/s<><73>", Global.agentTag, Utils.HumanFy(update.proxyUp), Utils.HumanFy(update.proxyDown));
SpeedDirectDisplay = string.Format("{0}:{1}/s<><73> | {2}/s<><73>", Global.directTag, Utils.HumanFy(update.directUp), Utils.HumanFy(update.directDown));
SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.agentTag, Utils.HumanFy(update.proxyUp), Utils.HumanFy(update.proxyDown));
SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.directTag, Utils.HumanFy(update.directUp), Utils.HumanFy(update.directDown));
if (update.proxyUp + update.proxyDown > 0)
{
@@ -623,27 +642,26 @@ namespace v2rayN.ViewModels
}
}
private void OnHotkeyHandler(object sender, HotkeyEventArgs e)
private void OnHotkeyHandler(EGlobalHotkey e)
{
switch (Utils.ToInt(e.Name))
switch (e)
{
case (int)EGlobalHotkey.ShowForm:
case EGlobalHotkey.ShowForm:
ShowHideWindow(null);
break;
case (int)EGlobalHotkey.SystemProxyClear:
case EGlobalHotkey.SystemProxyClear:
SetListenerType(ESysProxyType.ForcedClear);
break;
case (int)EGlobalHotkey.SystemProxySet:
case EGlobalHotkey.SystemProxySet:
SetListenerType(ESysProxyType.ForcedChange);
break;
case (int)EGlobalHotkey.SystemProxyUnchanged:
case EGlobalHotkey.SystemProxyUnchanged:
SetListenerType(ESysProxyType.Unchanged);
break;
case (int)EGlobalHotkey.SystemProxyPac:
case EGlobalHotkey.SystemProxyPac:
SetListenerType(ESysProxyType.Pac);
break;
}
e.Handled = true;
}
public void MyAppExit(bool blWindowsShutDown)
{
@@ -664,6 +682,8 @@ namespace v2rayN.ViewModels
SysProxyHandle.UpdateSysProxy(_config, true);
}
ProfileExHandler.Instance.SaveTo();
_statistics?.SaveTo();
_statistics?.Close();
@@ -689,10 +709,11 @@ namespace v2rayN.ViewModels
return;
}
_subId = SelectedSub?.id;
_config.subIndexId = _subId;
RefreshServers();
_updateView("ProfilesFocus");
_updateView(EViewAction.ProfilesFocus);
}
private void ServerFilterChanged(bool c)
@@ -702,25 +723,29 @@ namespace v2rayN.ViewModels
return;
}
_serverFilter = ServerFilter;
if (Utils.IsNullOrEmpty(_serverFilter))
{
RefreshServers();
}
}
private void RefreshServers()
public void RefreshServers()
{
List<ProfileItemModel> lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter);
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
ConfigHandler.SetDefaultServer(_config, _lstProfile);
ConfigHandler.SetDefaultServer(_config, lstModel);
List<ServerStatItem> lstServerStat = new();
if (_statistics != null && _statistics.Enable)
{
lstServerStat = _statistics.ServerStat;
}
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
lstModel = (from t in lstModel
join t2 in lstServerStat
on t.indexId equals t2.indexId into t2b
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
indexId = t.indexId,
@@ -731,16 +756,19 @@ namespace v2rayN.ViewModels
security = t.security,
network = t.network,
streamSecurity = t.streamSecurity,
subid = t.subid,
subRemarks = t.subRemarks,
isActive = t.indexId == _config.indexId,
delay = t.delay,
delayVal = t.delay != 0 ? $"{t.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t.speed != 0 ? $"{t.speed} {Global.SpeedUnit}" : string.Empty,
sort = t33 == null ? 0 : t33.sort,
delay = t33 == null ? 0 : t33.delay,
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).ToList();
}).OrderBy(t => t.sort).ToList();
_lstProfile = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(lstModel));
Application.Current.Dispatcher.Invoke((Action)(() =>
{
@@ -765,7 +793,14 @@ namespace v2rayN.ViewModels
var running = ConfigHandler.GetDefaultServer(ref _config);
if (running != null)
{
RunningServerDisplay = string.Format("{0}:{1}", ResUI.menuServers, running.GetSummary());
var runningSummary = running.GetSummary();
RunningServerDisplay = $"{ResUI.menuServers}:{runningSummary}";
RunningServerToolTipText = runningSummary;
}
else
{
RunningServerDisplay =
RunningServerToolTipText = ResUI.CheckServerSettings;
}
}));
}
@@ -775,9 +810,11 @@ namespace v2rayN.ViewModels
_servers.Clear();
if (_lstProfile.Count > _config.guiItem.trayMenuServersLimit)
{
BlServers = false;
return;
}
BlServers = true;
for (int k = 0; k < _lstProfile.Count; k++)
{
ProfileItem it = _lstProfile[k];
@@ -785,7 +822,7 @@ namespace v2rayN.ViewModels
var item = new ComboItem() { ID = it.indexId, Text = name };
_servers.Add(item);
if (_config.indexId.Equals(it.indexId))
if (_config.indexId == it.indexId)
{
SelectedServer = item;
}
@@ -801,20 +838,31 @@ namespace v2rayN.ViewModels
{
_subItems.Add(item);
}
if (_subId != null && _subItems.FirstOrDefault(t => t.id == _subId) != null)
{
SelectedSub = _subItems.FirstOrDefault(t => t.id == _subId);
}
else
{
SelectedSub = _subItems[0];
}
}
#endregion
#region Add Servers
private int GetProfileItems(out List<ProfileItem> lstSelecteds)
private int GetProfileItems(out List<ProfileItem> lstSelecteds, bool latest)
{
lstSelecteds = new List<ProfileItem>();
if (SelectedProfiles == null || SelectedProfiles.Count() <= 0)
if (SelectedProfiles == null || SelectedProfiles.Count <= 0)
{
return -1;
}
foreach (var profile in SelectedProfiles)
var orderProfiles = SelectedProfiles?.OrderBy(t => t.sort);
if (latest)
{
foreach (var profile in orderProfiles)
{
var item = LazyConfig.Instance.GetProfileItem(profile.indexId);
if (item is not null)
@@ -822,6 +870,12 @@ namespace v2rayN.ViewModels
lstSelecteds.Add(item);
}
}
}
else
{
lstSelecteds = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(orderProfiles));
}
return 0;
}
@@ -834,7 +888,6 @@ namespace v2rayN.ViewModels
{
subid = _subId,
configType = eConfigType,
displayLog = false
};
}
else
@@ -872,10 +925,11 @@ namespace v2rayN.ViewModels
public void AddServerViaClipboard()
{
string clipboardData = Utils.GetClipboardData();
int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData, _subId, false);
var clipboardData = Utils.GetClipboardData();
int ret = ConfigHandler.AddBatchServers(ref _config, clipboardData!, _subId, false);
if (ret > 0)
{
InitSubscriptionView();
RefreshServers();
_noticeHandler?.Enqueue(string.Format(ResUI.SuccessfullyImportedServerViaClipboard, ret));
}
@@ -884,9 +938,10 @@ namespace v2rayN.ViewModels
{
ShowHideWindow(false);
var dpiXY = Utils.GetDpiXY(Application.Current.MainWindow);
string result = await Task.Run(() =>
{
return Utils.ScanScreen();
return Utils.ScanScreen(dpiXY.Item1, dpiXY.Item2);
});
ShowHideWindow(true);
@@ -900,6 +955,7 @@ namespace v2rayN.ViewModels
int ret = ConfigHandler.AddBatchServers(ref _config, result, _subId, false);
if (ret > 0)
{
InitSubscriptionView();
RefreshServers();
_noticeHandler?.Enqueue(ResUI.SuccessfullyImportedServerViaScan);
}
@@ -907,12 +963,12 @@ namespace v2rayN.ViewModels
}
public void RemoveServer()
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds) < 0)
if (GetProfileItems(out List<ProfileItem> lstSelecteds, false) < 0)
{
return;
}
if (UI.ShowYesNo(ResUI.RemoveServer) == DialogResult.No)
if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No)
{
return;
}
@@ -930,15 +986,14 @@ namespace v2rayN.ViewModels
private void RemoveDuplicateServer()
{
int oldCount = _lstProfile.Count;
int newCount = ConfigHandler.DedupServerList(ref _config, ref _lstProfile);
var tuple = ConfigHandler.DedupServerList(_config, _subId);
RefreshServers();
Reload();
_noticeHandler?.Enqueue(string.Format(ResUI.RemoveDuplicateServerResult, oldCount, newCount));
_noticeHandler?.Enqueue(string.Format(ResUI.RemoveDuplicateServerResult, tuple.Item1, tuple.Item2));
}
private void CopyServer()
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds) < 0)
if (GetProfileItems(out List<ProfileItem> lstSelecteds, false) < 0)
{
return;
}
@@ -974,7 +1029,7 @@ namespace v2rayN.ViewModels
return;
}
if (ConfigHandler.SetDefaultServer(ref _config, item) == 0)
if (ConfigHandler.SetDefaultServerIndex(ref _config, indexId) == 0)
{
RefreshServers();
Reload();
@@ -1021,23 +1076,20 @@ namespace v2rayN.ViewModels
await DialogHost.Show(dialog, "RootDialog");
}
public void SortServer(int colIndex)
public void SortServer(string colName)
{
if (colIndex < 0)
if (Utils.IsNullOrEmpty(colName))
{
return;
}
if (!_dicHeaderSort.ContainsKey(colIndex))
{
_dicHeaderSort.Add(colIndex, true);
}
_dicHeaderSort.TryGetValue(colIndex, out bool asc);
if (ConfigHandler.SortServers(ref _config, _subId, (EServerColName)colIndex, asc) != 0)
_dicHeaderSort.TryAdd(colName, true);
_dicHeaderSort.TryGetValue(colName, out bool asc);
if (ConfigHandler.SortServers(ref _config, _subId, colName, asc) != 0)
{
return;
}
_dicHeaderSort[colIndex] = !asc;
_dicHeaderSort[colName] = !asc;
RefreshServers();
}
@@ -1070,7 +1122,7 @@ namespace v2rayN.ViewModels
return;
}
if (GetProfileItems(out List<ProfileItem> lstSelecteds) < 0)
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
{
return;
}
@@ -1121,7 +1173,7 @@ namespace v2rayN.ViewModels
{
SelectedProfiles = _profileItems;
}
if (GetProfileItems(out List<ProfileItem> lstSelecteds) < 0)
if (GetProfileItems(out List<ProfileItem> lstSelecteds, false) < 0)
{
return;
}
@@ -1153,12 +1205,12 @@ namespace v2rayN.ViewModels
public void Export2ShareUrl()
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds) < 0)
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
{
return;
}
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
foreach (var it in lstSelecteds)
{
string url = ShareHandler.GetShareUrl(it);
@@ -1178,15 +1230,15 @@ namespace v2rayN.ViewModels
private void Export2SubContent()
{
if (GetProfileItems(out List<ProfileItem> lstSelecteds) < 0)
if (GetProfileItems(out List<ProfileItem> lstSelecteds, true) < 0)
{
return;
}
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
foreach (var it in lstSelecteds)
{
string url = ShareHandler.GetShareUrl(it);
string? url = ShareHandler.GetShareUrl(it);
if (Utils.IsNullOrEmpty(url))
{
continue;
@@ -1255,14 +1307,32 @@ namespace v2rayN.ViewModels
}
}
private void RebootAsAdmin()
{
ProcessStartInfo startInfo = new()
{
UseShellExecute = true,
Arguments = Global.RebootAs,
WorkingDirectory = Utils.StartupPath(),
FileName = Utils.GetExePath(),
Verb = "runas",
};
try
{
Process.Start(startInfo);
MyAppExit(false);
}
catch { }
}
private void ImportOldGuiConfig()
{
OpenFileDialog fileDialog = new OpenFileDialog
OpenFileDialog fileDialog = new()
{
Multiselect = false,
Filter = "guiNConfig|*.json|All|*.*"
};
if (fileDialog.ShowDialog() != DialogResult.OK)
if (fileDialog.ShowDialog() != true)
{
return;
}
@@ -1349,7 +1419,6 @@ namespace v2rayN.ViewModels
public void Reload()
{
Global.reloadCore = true;
_ = LoadV2ray();
}
@@ -1369,7 +1438,6 @@ namespace v2rayN.ViewModels
{
_coreHandler.LoadCore(_config);
Global.reloadCore = false;
//ConfigHandler.SaveConfig(ref _config, false);
ChangeSystemProxyStatus(_config.sysProxyType, false);
@@ -1445,7 +1513,7 @@ namespace v2rayN.ViewModels
foreach (var item in routings)
{
_routingItems.Add(item);
if (item.id.Equals(_config.routingBasicItem.routingIndexId))
if (item.id == _config.routingBasicItem.routingIndexId)
{
SelectedRouting = item;
}
@@ -1521,7 +1589,7 @@ namespace v2rayN.ViewModels
public void ShowHideWindow(bool? blShow)
{
var bl = blShow.HasValue ? blShow.Value : !Global.ShowInTaskbar;
var bl = blShow ?? !Global.ShowInTaskbar;
if (bl)
{
//Application.Current.MainWindow.ShowInTaskbar = true;
@@ -1640,7 +1708,7 @@ namespace v2rayN.ViewModels
public void InboundDisplayStaus()
{
StringBuilder sb = new StringBuilder();
StringBuilder sb = new();
sb.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}]");
sb.Append(" | ");
//if (_config.sysProxyType == ESysProxyType.ForcedChange)
@@ -1651,21 +1719,21 @@ namespace v2rayN.ViewModels
//{
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].newPort4LAN)
{
StringBuilder sb2 = new StringBuilder();
StringBuilder sb2 = new();
sb2.Append($"[{Global.InboundSocks}:{LazyConfig.Instance.GetLocalPort(Global.InboundSocks2)}]");
sb2.Append(" | ");
sb2.Append($"[{Global.InboundHttp}:{LazyConfig.Instance.GetLocalPort(Global.InboundHttp2)}]");
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2.ToString()}";
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}";
}
else
{
InboundLanDisplay = $"{ResUI.LabLAN}:{sb.ToString()}";
InboundLanDisplay = $"{ResUI.LabLAN}:{sb}";
}
}
else
@@ -1702,10 +1770,10 @@ namespace v2rayN.ViewModels
.Delay(TimeSpan.FromSeconds(1))
.Subscribe(x =>
{
Application.Current.Dispatcher.Invoke((Action)(() =>
Application.Current.Dispatcher.Invoke(() =>
{
ShowHideWindow(false);
}));
});
});
}
}

View File

@@ -60,11 +60,11 @@ namespace v2rayN.ViewModels
[Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int autoUpdateInterval { get; set; }
[Reactive] public int autoUpdateSubInterval { get; set; }
[Reactive] public int trayMenuServersLimit { get; set; }
[Reactive] public string currentFontFamily { get; set; }
[Reactive] public int SpeedTestTimeout { get; set; }
[Reactive] public string SpeedTestUrl { get; set; }
[Reactive] public bool EnableHWA { get; set; }
#endregion
@@ -75,6 +75,7 @@ namespace v2rayN.ViewModels
#region Tun mode
[Reactive] public bool TunShowWindow { get; set; }
[Reactive] public bool TunEnabledLog { get; set; }
[Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; }
@@ -83,8 +84,10 @@ namespace v2rayN.ViewModels
[Reactive] public bool TunBypassMode2 { get; set; }
[Reactive] public string TunDirectIP { get; set; }
[Reactive] public string TunDirectProcess { get; set; }
[Reactive] public string TunDirectDNS { get; set; }
[Reactive] public string TunProxyIP { get; set; }
[Reactive] public string TunProxyProcess { get; set; }
[Reactive] public string TunProxyDNS { get; set; }
#endregion
#region CoreType
@@ -152,11 +155,11 @@ namespace v2rayN.ViewModels
EnableDragDropSort = _config.uiItem.enableDragDropSort;
DoubleClick2Activate = _config.uiItem.doubleClick2Activate;
autoUpdateInterval = _config.guiItem.autoUpdateInterval;
autoUpdateSubInterval = _config.guiItem.autoUpdateSubInterval;
trayMenuServersLimit = _config.guiItem.trayMenuServersLimit;
currentFontFamily = _config.uiItem.currentFontFamily;
SpeedTestTimeout = _config.speedTestItem.speedTestTimeout;
SpeedTestUrl = _config.speedTestItem.speedTestUrl;
EnableHWA = _config.guiItem.enableHWA;
#endregion
@@ -168,6 +171,7 @@ namespace v2rayN.ViewModels
#region Tun mode
TunShowWindow = _config.tunModeItem.showWindow;
TunEnabledLog = _config.tunModeItem.enabledLog;
TunStrictRoute = _config.tunModeItem.strictRoute;
TunStack = _config.tunModeItem.stack;
TunMtu = _config.tunModeItem.mtu;
@@ -175,8 +179,10 @@ namespace v2rayN.ViewModels
TunBypassMode = _config.tunModeItem.bypassMode;
TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true);
TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true);
TunDirectDNS = _config.tunModeItem.directDNS;
TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true);
TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true);
TunProxyDNS = _config.tunModeItem.proxyDNS;
this.WhenAnyValue(
x => x.TunBypassMode)
.Subscribe(c => TunBypassMode2 = !TunBypassMode);
@@ -251,7 +257,7 @@ namespace v2rayN.ViewModels
}
var obj = Utils.ParseJson(remoteDNS);
if (obj != null && obj.ContainsKey("servers"))
if (obj?.ContainsKey("servers") == true)
{
}
else
@@ -275,7 +281,7 @@ namespace v2rayN.ViewModels
//}
//Core
_config.inbound[0].localPort = Utils.ToInt(localPort);
_config.inbound[0].localPort = localPort;
_config.inbound[0].udpEnabled = udpEnabled;
_config.inbound[0].sniffingEnabled = sniffingEnabled;
_config.inbound[0].routeOnly = routeOnly;
@@ -325,7 +331,6 @@ namespace v2rayN.ViewModels
_config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.uiItem.autoHideStartup = AutoHideStartup;
_config.guiItem.autoUpdateInterval = autoUpdateInterval;
_config.guiItem.autoUpdateSubInterval = autoUpdateSubInterval;
_config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.uiItem.enableDragDropSort = EnableDragDropSort;
_config.uiItem.doubleClick2Activate = DoubleClick2Activate;
@@ -333,6 +338,7 @@ namespace v2rayN.ViewModels
_config.uiItem.currentFontFamily = currentFontFamily;
_config.speedTestItem.speedTestTimeout = SpeedTestTimeout;
_config.speedTestItem.speedTestUrl = SpeedTestUrl;
_config.guiItem.enableHWA = EnableHWA;
//systemProxy
_config.systemProxyExceptions = systemProxyExceptions;
@@ -340,6 +346,7 @@ namespace v2rayN.ViewModels
//tun mode
_config.tunModeItem.showWindow = TunShowWindow;
_config.tunModeItem.enabledLog = TunEnabledLog;
_config.tunModeItem.strictRoute = TunStrictRoute;
_config.tunModeItem.stack = TunStack;
_config.tunModeItem.mtu = TunMtu;
@@ -347,8 +354,10 @@ namespace v2rayN.ViewModels
_config.tunModeItem.bypassMode = TunBypassMode;
_config.tunModeItem.directIP = Utils.String2List(TunDirectIP);
_config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess);
_config.tunModeItem.directDNS = Utils.ToJson(Utils.ParseJson(TunDirectDNS));
_config.tunModeItem.proxyIP = Utils.String2List(TunProxyIP);
_config.tunModeItem.proxyProcess = Utils.String2List(TunProxyProcess);
_config.tunModeItem.proxyDNS = Utils.ToJson(Utils.ParseJson(TunProxyDNS));
//coreType
SaveCoreType();

View File

@@ -1,10 +1,10 @@
using DynamicData.Binding;
using Microsoft.Win32;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Windows;
using System.Windows.Forms;
using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
@@ -173,7 +173,7 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.PleaseSelectRules);
return;
}
if (UI.ShowYesNo(ResUI.RemoveRules) == DialogResult.No)
if (UI.ShowYesNo(ResUI.RemoveRules) == MessageBoxResult.No)
{
return;
}
@@ -268,7 +268,7 @@ namespace v2rayN.ViewModels
Multiselect = false,
Filter = "Rules|*.json|All|*.*"
};
if (fileDialog.ShowDialog() != DialogResult.OK)
if (fileDialog.ShowDialog() != true)
{
return;
}
@@ -299,7 +299,7 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.OperationSuccess);
}
}
private void ImportRulesFromUrl()
private async Task ImportRulesFromUrl()
{
var url = SelectedRouting.url;
if (Utils.IsNullOrEmpty(url))
@@ -308,10 +308,8 @@ namespace v2rayN.ViewModels
return;
}
Task.Run(async () =>
{
DownloadHandle downloadHandle = new DownloadHandle();
string result = await downloadHandle.DownloadStringAsync(url, false, "");
string result = await downloadHandle.TryDownloadString(url, true, "");
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{
Application.Current.Dispatcher.Invoke((Action)(() =>
@@ -320,12 +318,11 @@ namespace v2rayN.ViewModels
}));
UI.Show(ResUI.OperationSuccess);
}
});
}
private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData)
{
bool blReplace = false;
if (UI.ShowYesNo(ResUI.AddBatchRoutingRulesYesNo) == DialogResult.No)
if (UI.ShowYesNo(ResUI.AddBatchRoutingRulesYesNo) == MessageBoxResult.No)
{
blReplace = true;
}

View File

@@ -4,7 +4,6 @@ using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Windows;
using System.Windows.Forms;
using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
@@ -163,7 +162,7 @@ namespace v2rayN.ViewModels
foreach (var item in routings)
{
bool def = false;
if (item.id.Equals(_config.routingBasicItem.routingIndexId))
if (item.id == _config.routingBasicItem.routingIndexId)
{
def = true;
}
@@ -244,7 +243,7 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.PleaseSelectRules);
return;
}
if (UI.ShowYesNo(ResUI.RemoveRules) == DialogResult.No)
if (UI.ShowYesNo(ResUI.RemoveRules) == MessageBoxResult.No)
{
return;
}

View File

@@ -62,7 +62,9 @@ namespace v2rayN.ViewModels
{
item.remarks = SelectedSource.remarks;
item.url = SelectedSource.url;
item.moreUrl = SelectedSource.moreUrl;
item.enabled = SelectedSource.enabled;
item.autoUpdateInterval = SelectedSource.autoUpdateInterval;
item.userAgent = SelectedSource.userAgent;
item.sort = SelectedSource.sort;
item.filter = SelectedSource.filter;

View File

@@ -6,7 +6,6 @@ using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive;
using System.Windows;
using System.Windows.Forms;
using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
@@ -24,6 +23,7 @@ namespace v2rayN.ViewModels
public IObservableCollection<SubItem> SubItems => _subItems;
[Reactive]
public SubItem SelectedSource { get; set; }
public IList<SubItem> SelectedSources { get; set; }
public ReactiveCommand<Unit, Unit> SubAddCmd { get; }
public ReactiveCommand<Unit, Unit> SubDeleteCmd { get; }
@@ -96,12 +96,15 @@ namespace v2rayN.ViewModels
private void DeleteSub()
{
if (UI.ShowYesNo(ResUI.RemoveServer) == DialogResult.No)
if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No)
{
return;
}
ConfigHandler.DeleteSubItem(ref _config, SelectedSource?.id);
foreach (var it in SelectedSources)
{
ConfigHandler.DeleteSubItem(ref _config, it?.id);
}
RefreshSubItems();
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
IsModified = true;

View File

@@ -18,6 +18,7 @@
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
@@ -136,12 +137,19 @@
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbDisplayLog}" />
<ToggleButton
x:Name="togDisplayLog"
<StackPanel
Grid.Row="4"
Grid.Column="1"
Margin="4"
HorizontalAlignment="Left" />
Orientation="Horizontal">
<ToggleButton x:Name="togDisplayLog" HorizontalAlignment="Left" />
<TextBlock
Margin="8,0"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TipDisplayLog}" />
</StackPanel>
<TextBlock
Grid.Row="5"
@@ -175,7 +183,7 @@
<Grid
Grid.Row="1"
Margin="16"
Margin="8"
HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />

View File

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

View File

@@ -10,12 +10,13 @@
xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuServers}"
Width="800"
Height="800"
Width="820"
Height="820"
x:TypeArguments="vms:AddServerViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
@@ -558,8 +559,10 @@
Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" />
</Grid>
<Grid x:Name="gridTlsMore" Grid.Row="7">
<Grid
x:Name="gridTlsMore"
Grid.Row="7"
Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@@ -594,25 +597,10 @@
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAllowInsecure}" />
<ComboBox
x:Name="cmbAllowInsecure"
Grid.Row="2"
Grid.Column="1"
Width="100"
Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFingerprint}" />
<ComboBox
x:Name="cmbFingerprint"
Grid.Row="3"
Grid.Row="2"
Grid.Column="1"
Width="200"
Margin="{StaticResource ServerItemMargin}"
@@ -620,7 +608,7 @@
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="4"
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
@@ -628,13 +616,125 @@
Text="{x:Static resx:ResUI.TbAlpn}" />
<ComboBox
x:Name="cmbAlpn"
Grid.Row="4"
Grid.Row="3"
Grid.Column="1"
Width="200"
Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" />
</Grid>
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAllowInsecure}" />
<ComboBox
x:Name="cmbAllowInsecure"
Grid.Row="4"
Grid.Column="1"
Width="100"
Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" />
</Grid>
<Grid
x:Name="gridRealityMore"
Grid.Row="7"
Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSNI}" />
<TextBox
x:Name="txtSNI2"
Grid.Row="0"
Grid.Column="1"
Width="400"
Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFingerprint}" />
<ComboBox
x:Name="cmbFingerprint2"
Grid.Row="1"
Grid.Column="1"
Width="200"
Margin="{StaticResource ServerItemMargin}"
IsEditable="True"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPublicKey}" />
<TextBox
x:Name="txtPublicKey"
Grid.Row="2"
Grid.Column="1"
Width="400"
Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbShortId}" />
<TextBox
x:Name="txtShortId"
Grid.Row="3"
Grid.Column="1"
Width="200"
Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSpiderX}" />
<TextBox
x:Name="txtSpiderX"
Grid.Row="4"
Grid.Column="1"
Width="400"
Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
</Grid>
<Separator
Grid.Row="8"
Margin="0,2"
@@ -642,7 +742,7 @@
<Grid
Grid.Row="9"
Margin="16"
Margin="8"
HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />

View File

@@ -16,6 +16,7 @@ namespace v2rayN.Views
public AddServerWindow(ProfileItem profileItem)
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded;
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
@@ -38,6 +39,7 @@ namespace v2rayN.Views
Global.fingerprints.ForEach(it =>
{
cmbFingerprint.Items.Add(it);
cmbFingerprint2.Items.Add(it);
});
Global.allowInsecures.ForEach(it =>
{
@@ -73,8 +75,8 @@ namespace v2rayN.Views
break;
case EConfigType.VLESS:
gridVLESS.Visibility = Visibility.Visible;
cmbStreamSecurity.Items.Add(Global.StreamSecurityX);
Global.xtlsFlows.ForEach(it =>
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
Global.flows.ForEach(it =>
{
cmbFlow5.Items.Add(it);
});
@@ -85,8 +87,7 @@ namespace v2rayN.Views
break;
case EConfigType.Trojan:
gridTrojan.Visibility = Visibility.Visible;
cmbStreamSecurity.Items.Add(Global.StreamSecurityX);
Global.xtlsFlows.ForEach(it =>
Global.flows.ForEach(it =>
{
cmbFlow6.Items.Add(it);
});
@@ -137,6 +138,13 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.SelectedSource.allowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.fingerprint, v => v.cmbFingerprint.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.alpn, v => v.cmbAlpn.Text).DisposeWith(disposables);
//reality
this.Bind(ViewModel, vm => vm.SelectedSource.sni, v => v.txtSNI2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.fingerprint, v => v.cmbFingerprint2.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.publicKey, v => v.txtPublicKey.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.shortId, v => v.txtShortId.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.spiderX, v => v.txtSpiderX.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
@@ -158,13 +166,20 @@ namespace v2rayN.Views
private void CmbStreamSecurity_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var security = cmbStreamSecurity.SelectedItem.ToString();
if (Utils.IsNullOrEmpty(security))
if (security == Global.StreamSecurityReality)
{
gridRealityMore.Visibility = Visibility.Visible;
gridTlsMore.Visibility = Visibility.Hidden;
}
else if (security == Global.StreamSecurity)
{
gridRealityMore.Visibility = Visibility.Hidden;
gridTlsMore.Visibility = Visibility.Visible;
}
else
{
gridTlsMore.Visibility = Visibility.Visible;
gridRealityMore.Visibility = Visibility.Hidden;
gridTlsMore.Visibility = Visibility.Hidden;
}
}
private void btnGUID_Click(object sender, RoutedEventArgs e)
@@ -184,12 +199,12 @@ namespace v2rayN.Views
return;
}
if (network.Equals(Global.DefaultNetwork))
if (network == Global.DefaultNetwork)
{
cmbHeaderType.Items.Add(Global.None);
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);
Global.kcpHeaderTypes.ForEach(it =>
@@ -197,7 +212,7 @@ namespace v2rayN.Views
cmbHeaderType.Items.Add(it);
});
}
else if (network.Equals("grpc"))
else if (network == "grpc")
{
cmbHeaderType.Items.Add(Global.GrpcgunMode);
cmbHeaderType.Items.Add(Global.GrpcmultiMode);
@@ -221,37 +236,34 @@ namespace v2rayN.Views
tipPath.Text =
tipHeaderType.Text = string.Empty;
if (network.Equals(Global.DefaultNetwork))
switch (network)
{
case Global.DefaultNetwork:
tipRequestHost.Text = ResUI.TransportRequestHostTip1;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip1;
}
else if (network.Equals("kcp"))
{
break;
case "kcp":
tipHeaderType.Text = ResUI.TransportHeaderTypeTip2;
tipPath.Text = ResUI.TransportPathTip5;
}
else if (network.Equals("ws"))
{
break;
case "ws":
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
}
else if (network.Equals("h2"))
{
break;
case "h2":
tipRequestHost.Text = ResUI.TransportRequestHostTip3;
tipPath.Text = ResUI.TransportPathTip2;
}
else if (network.Equals("quic"))
{
break;
case "quic":
tipRequestHost.Text = ResUI.TransportRequestHostTip4;
tipPath.Text = ResUI.TransportPathTip3;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip3;
}
else if (network.Equals("grpc"))
{
break;
case "grpc":
tipPath.Text = ResUI.TransportPathTip4;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
labHeaderType.Visibility = Visibility.Hidden;
break;
}
}

View File

@@ -18,6 +18,7 @@
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
KeyDown="GlobalHotkeySettingWindow_KeyDown"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
@@ -149,7 +150,7 @@
<Grid
Grid.Row="2"
Margin="16"
Margin="8"
HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />

View File

@@ -1,46 +1,24 @@
using System.Windows;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using v2rayN.Handler;
using v2rayN.Mode;
using v2rayN.Resx;
using Forms = System.Windows.Forms;
namespace v2rayN.Views
{
public partial class GlobalHotkeySettingWindow
{
private static Config _config;
List<KeyEventItem> lstKey;
private static Config _config = default!;
private Dictionary<object, KeyEventItem> _TextBoxKeyEventItem = default!;
public GlobalHotkeySettingWindow()
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = LazyConfig.Instance.GetConfig();
if (_config.globalHotkeys == null)
{
_config.globalHotkeys = new List<KeyEventItem>();
}
foreach (EGlobalHotkey it in Enum.GetValues(typeof(EGlobalHotkey)))
{
if (_config.globalHotkeys.FindIndex(t => t.eGlobalHotkey == it) >= 0)
{
continue;
}
_config.globalHotkeys.Add(new KeyEventItem()
{
eGlobalHotkey = it,
Alt = false,
Control = false,
Shift = false,
KeyCode = null
});
}
lstKey = Utils.DeepCopy(_config.globalHotkeys);
_config.globalHotkeys ??= new List<KeyEventItem>();
txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_KeyDown;
txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_KeyDown;
@@ -48,67 +26,84 @@ namespace v2rayN.Views
txtGlobalHotkey3.KeyDown += TxtGlobalHotkey_KeyDown;
txtGlobalHotkey4.KeyDown += TxtGlobalHotkey_KeyDown;
BindingData(-1);
HotkeyHandler.Instance.IsPause = true;
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
Utils.SetDarkBorder(this, _config.uiItem.colorModeDark);
InitData();
}
private void InitData()
{
_TextBoxKeyEventItem = new()
{
{ txtGlobalHotkey0,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.ShowForm) },
{ txtGlobalHotkey1,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyClear) },
{ txtGlobalHotkey2,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxySet) },
{ txtGlobalHotkey3,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyUnchanged)},
{ txtGlobalHotkey4,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyPac)}
};
BindingData();
}
private void TxtGlobalHotkey_KeyDown(object sender, KeyEventArgs e)
{
var txt = ((TextBox)sender);
var index = Utils.ToInt(txt.Name.Substring(txt.Name.Length - 1, 1));
if (e.Key == Key.System)
return;
var formsKey = (Forms.Keys)KeyInterop.VirtualKeyFromKey(e.Key);
lstKey[index].KeyCode = formsKey;
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);
e.Handled = true;
var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift,
Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin};
_TextBoxKeyEventItem[sender].KeyCode = e.Key == Key.System ? (_ModifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (_ModifierKeys.Contains(e.Key) ? Key.None : e.Key);
_TextBoxKeyEventItem[sender].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
_TextBoxKeyEventItem[sender].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
_TextBoxKeyEventItem[sender].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
(sender as TextBox)!.Text = KeyEventItemToString(_TextBoxKeyEventItem[sender]);
}
private void BindingData(int index)
private KeyEventItem GetKeyEventItemByEGlobalHotkey(List<KeyEventItem> KELsit, EGlobalHotkey eg)
{
for (int k = 0; k < lstKey.Count; k++)
return Utils.DeepCopy(KELsit.Find((it) => it.eGlobalHotkey == eg) ?? new()
{
if (index >= 0 && index != k)
{
continue;
}
var item = lstKey[k];
var keys = string.Empty;
eGlobalHotkey = eg,
Control = false,
Alt = false,
Shift = false,
KeyCode = null
});
if (item.Control)
{
keys += $"{Forms.Keys.Control.ToString()} + ";
}
if (item.Alt)
private string KeyEventItemToString(KeyEventItem item)
{
keys += $"{Forms.Keys.Alt.ToString()} + ";
}
if (item.Shift)
{
keys += $"{Forms.Keys.Shift.ToString()} + ";
}
if (item.KeyCode != null)
{
keys += $"{item.KeyCode.ToString()}";
}
var res = new StringBuilder();
SetText($"txtGlobalHotkey{k}", keys);
if (item.Control) res.Append($"{ModifierKeys.Control}+");
if (item.Shift) res.Append($"{ModifierKeys.Shift}+");
if (item.Alt) res.Append($"{ModifierKeys.Alt}+");
if (item.KeyCode != null && item.KeyCode != Key.None)
res.Append($"{item.KeyCode}");
return res.ToString();
}
private void BindingData()
{
foreach (var item in _TextBoxKeyEventItem)
{
if (item.Value.KeyCode != null && item.Value.KeyCode != Key.None)
{
(item.Key as TextBox)!.Text = KeyEventItemToString(item.Value);
}
else
{
(item.Key as TextBox)!.Text = string.Empty;
}
}
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
_config.globalHotkeys = lstKey;
_config.globalHotkeys = _TextBoxKeyEventItem.Values.ToList();
if (ConfigHandler.SaveConfig(ref _config, false) == 0)
{
HotkeyHandler.Instance.ReLoad();
this.DialogResult = true;
}
else
@@ -124,37 +119,14 @@ namespace v2rayN.Views
private void btnReset_Click(object sender, RoutedEventArgs e)
{
lstKey.Clear();
foreach (EGlobalHotkey it in Enum.GetValues(typeof(EGlobalHotkey)))
foreach (var k in _TextBoxKeyEventItem.Keys)
{
if (lstKey.FindIndex(t => t.eGlobalHotkey == it) >= 0)
{
continue;
}
lstKey.Add(new KeyEventItem()
{
eGlobalHotkey = it,
Alt = false,
Control = false,
Shift = false,
KeyCode = null
});
}
BindingData(-1);
}
private void SetText(string name, string txt)
{
foreach (UIElement element in gridText.Children)
{
if (element is TextBox)
{
if (((TextBox)element).Name == name)
{
((TextBox)element).Text = txt;
}
}
_TextBoxKeyEventItem[k].Alt = false;
_TextBoxKeyEventItem[k].Control = false;
_TextBoxKeyEventItem[k].Shift = false;
_TextBoxKeyEventItem[k].KeyCode = Key.None;
}
BindingData();
}
private void GlobalHotkeySettingWindow_KeyDown(object sender, KeyEventArgs e)

View File

@@ -10,13 +10,13 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:tb="clr-namespace:H.NotifyIcon;assembly=H.NotifyIcon.Wpf"
xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="v2rayN"
Width="900"
Height="700"
MinWidth="800"
MinHeight="600"
MinWidth="900"
MinHeight="700"
x:TypeArguments="vms:MainWindowViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
@@ -53,7 +53,10 @@
<MenuItem Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -99,7 +102,10 @@
<MenuItem Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -131,7 +137,10 @@
<MenuItem Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -148,6 +157,10 @@
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGlobalHotkeySetting}" />
<Separator Margin="-40,5" />
<MenuItem
x:Name="menuRebootAsAdmin"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRebootAsAdmin}" />
<MenuItem
x:Name="menuSettingsSetUWP"
Height="{StaticResource MenuItemHeight}"
@@ -169,7 +182,10 @@
<MenuItem x:Name="menuReload" Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -180,7 +196,10 @@
<MenuItem Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -210,6 +229,11 @@
Height="{StaticResource MenuItemHeight}"
Header="Clash.Meta Core" />
<Separator Margin="-40,5" />
<MenuItem
x:Name="menuCheckUpdateSingBoxCore"
Height="{StaticResource MenuItemHeight}"
Header="SingBox Core" />
<Separator Margin="-40,5" />
<MenuItem
x:Name="menuCheckUpdateGeo"
Height="{StaticResource MenuItemHeight}"
@@ -221,7 +245,10 @@
<MenuItem x:Name="menuHelp" Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -235,7 +262,10 @@
Click="menuPromotion_Click">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -249,7 +279,10 @@
Click="menuClose_Click">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -259,6 +292,7 @@
<materialDesign:PopupBox
Padding="8,0"
HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
<StackPanel Margin="8">
<Grid>
@@ -333,12 +367,7 @@
</materialDesign:PopupBox>
</ToolBar>
</ToolBarTray>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar
HorizontalAlignment="Center"
VerticalAlignment="Center"
ClipToBounds="True"
Style="{StaticResource MaterialDesignToolBar}">
<WrapPanel Margin="2" DockPanel.Dock="Top">
<ListBox
x:Name="lstGroup"
FontSize="{DynamicResource StdFontSize}"
@@ -356,18 +385,25 @@
Height="30"
Margin="4,0"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
<materialDesign:PackIcon Kind="Plus" />
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
</Button>
<Button
x:Name="btnAutofitColumnWidth"
Width="30"
Height="30"
Margin="4,0"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
</Button>
<Separator />
<TextBox
x:Name="txtServerFilter"
Width="100"
Width="200"
Margin="4,0"
VerticalContentAlignment="Center"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
materialDesign:TextFieldAssist.HasClearButton="True"
Style="{StaticResource DefTextBox}" />
</ToolBar>
</ToolBarTray>
</WrapPanel>
<materialDesign:ColorZone
Height="50"
@@ -468,6 +504,7 @@
GridLinesVisibility="All"
HeadersVisibility="All"
IsReadOnly="True"
RowHeaderWidth="40"
Style="{StaticResource DefDataGrid}">
<DataGrid.InputBindings>
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" />
@@ -545,6 +582,7 @@
</MenuItem.Header>
</MenuItem>
</MenuItem>
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
<MenuItem
x:Name="menuMoveTop"
Height="{StaticResource MenuItemHeight}"
@@ -561,6 +599,7 @@
x:Name="menuMoveBottom"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}" />
</MenuItem>
<MenuItem
x:Name="menuSelectAll"
Height="{StaticResource MenuItemHeight}"
@@ -593,55 +632,64 @@
<Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
<EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding isActive}" Value="True">
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryHueLightBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Width="50">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border
Width="auto"
Height="auto"
Background="{DynamicResource PrimaryHueLightBrush}"
Visibility="{Binding Path=isActive, Converter={StaticResource BoolToVisConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<materialDesign:DataGridTextColumn
<base:MyDGTextColumn
Width="80"
Binding="{Binding configType}"
ExName="configType"
Header="{x:Static resx:ResUI.LvServiceType}" />
<DataGridTextColumn
<base:MyDGTextColumn
Width="150"
Binding="{Binding remarks}"
Header="{x:Static resx:ResUI.LvAlias}" />
<DataGridTextColumn
ExName="remarks"
Header="{x:Static resx:ResUI.LvRemarks}" />
<base:MyDGTextColumn
Width="120"
Binding="{Binding address}"
ExName="address"
Header="{x:Static resx:ResUI.LvAddress}" />
<DataGridTextColumn
<base:MyDGTextColumn
Width="60"
Binding="{Binding port}"
ExName="port"
Header="{x:Static resx:ResUI.LvPort}" />
<DataGridTextColumn
<base:MyDGTextColumn
Width="100"
Binding="{Binding security}"
ExName="security"
Header="{x:Static resx:ResUI.LvEncryptionMethod}" />
<DataGridTextColumn
<base:MyDGTextColumn
Width="100"
Binding="{Binding network}"
ExName="network"
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
<DataGridTextColumn
<base:MyDGTextColumn
Width="100"
Binding="{Binding streamSecurity}"
ExName="streamSecurity"
Header="{x:Static resx:ResUI.LvTLS}" />
<DataGridTextColumn
<base:MyDGTextColumn
Width="100"
Binding="{Binding subRemarks}"
ExName="subRemarks"
Header="{x:Static resx:ResUI.LvSubscription}" />
<DataGridTextColumn
<base:MyDGTextColumn
Width="100"
Binding="{Binding delayVal}"
ExName="delayVal"
Header="{x:Static resx:ResUI.LvTestDelay}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
@@ -649,37 +697,42 @@
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn
</base:MyDGTextColumn>
<base:MyDGTextColumn
Width="100"
Binding="{Binding speedVal}"
ExName="speedVal"
Header="{x:Static resx:ResUI.LvTestSpeed}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</base:MyDGTextColumn>
<DataGridTextColumn
<base:MyDGTextColumn
x:Name="colTodayUp"
Width="100"
Binding="{Binding todayUp}"
ExName="todayUp"
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
<DataGridTextColumn
<base:MyDGTextColumn
x:Name="colTodayDown"
Width="100"
Binding="{Binding todayDown}"
ExName="todayDown"
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
<DataGridTextColumn
<base:MyDGTextColumn
x:Name="colTotalUp"
Width="100"
Binding="{Binding totalUp}"
ExName="totalUp"
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
<DataGridTextColumn
<base:MyDGTextColumn
x:Name="colTotalDown"
Width="100"
Binding="{Binding totalDown}"
ExName="totalDown"
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
</DataGrid.Columns>
@@ -701,6 +754,7 @@
<materialDesign:PackIcon
x:Name="menuSystemProxyClear2"
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" />
</StackPanel>
@@ -712,6 +766,7 @@
<materialDesign:PackIcon
x:Name="menuSystemProxySet2"
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" />
</StackPanel>
@@ -723,6 +778,7 @@
<materialDesign:PackIcon
x:Name="menuSystemProxyNothing2"
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" />
</StackPanel>
@@ -734,12 +790,13 @@
<materialDesign:PackIcon
x:Name="menuSystemProxyPac2"
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" />
</StackPanel>
</MenuItem.Header>
</MenuItem>
<Separator />
<Separator x:Name="sepRoutings" />
<MenuItem x:Name="menuRoutings" Height="Auto">
<MenuItem.Header>
<DockPanel>
@@ -791,6 +848,22 @@
Header="{x:Static resx:ResUI.menuExit}" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
<tb:TaskbarIcon.TrayToolTip>
<Border
Width="Auto"
Height="Auto"
Background="{DynamicResource MaterialDesignLightBackground}"
BorderBrush="{DynamicResource MaterialDesignDarkBackground}"
BorderThickness="0"
CornerRadius="4">
<TextBlock
Margin="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{DynamicResource MaterialDesignDarkBackground}"
Text="{Binding Mode=OneWay, Path=ToolTipText}" />
</Border>
</tb:TaskbarIcon.TrayToolTip>
</tb:TaskbarIcon>
<materialDesign:Snackbar x:Name="MainSnackbar" MessageQueue="{materialDesign:MessageQueue}" />
</Grid>

View File

@@ -1,7 +1,6 @@
using ReactiveUI;
using Splat;
using System.ComponentModel;
using System.Drawing;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
@@ -9,12 +8,12 @@ using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
using v2rayN.Resx;
using v2rayN.ViewModels;
using Point = System.Windows.Point;
using SystemInformation = System.Windows.Forms.SystemInformation;
namespace v2rayN.Views
{
@@ -30,6 +29,8 @@ namespace v2rayN.Views
App.Current.SessionEnding += Current_SessionEnding;
this.Closing += MainWindow_Closing;
this.PreviewKeyDown += MainWindow_PreviewKeyDown;
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
@@ -117,6 +118,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.OptionSettingCmd, v => v.menuOptionSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingSettingCmd, v => v.menuRoutingSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.GlobalHotkeySettingCmd, v => v.menuGlobalHotkeySetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RebootAsAdminCmd, v => v.menuRebootAsAdmin).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ClearServerStatisticsCmd, v => v.menuClearServerStatistics).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportOldGuiConfigCmd, v => v.menuImportOldGuiConfig).DisposeWith(disposables);
@@ -127,6 +129,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.CheckUpdateXrayCoreCmd, v => v.menuCheckUpdateXrayCore).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateClashCoreCmd, v => v.menuCheckUpdateClashCore).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateClashMetaCoreCmd, v => v.menuCheckUpdateClashMetaCore).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateSingBoxCoreCmd, v => v.menuCheckUpdateSingBoxCore).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateGeoCmd, v => v.menuCheckUpdateGeo).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
@@ -146,9 +149,11 @@ namespace v2rayN.Views
this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings.SelectedItem).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.menuRoutings.Visibility).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.sepRoutings.Visibility).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables);
//tray menu
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables);
@@ -157,6 +162,7 @@ namespace v2rayN.Views
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.RunningServerToolTipText, v => v.tbNotify.ToolTipText).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);
@@ -189,23 +195,30 @@ namespace v2rayN.Views
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed;
//if (_config.uiItem.autoHideStartup)
//{
// WindowState = WindowState.Minimized;
//}
if (!_config.guiItem.enableHWA)
{
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
}
}
#region Event
private void UpdateViewHandler(string action)
private void UpdateViewHandler(EViewAction action)
{
if (action == "AdjustMainLvColWidth")
if (action == EViewAction.AdjustMainLvColWidth)
{
Application.Current.Dispatcher.Invoke((Action)(() =>
Application.Current.Dispatcher.Invoke(() =>
{
foreach (var it in lstProfiles.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
AutofitColumnWidth();
});
}
}));
}
else if (action == "ProfilesFocus")
else if (action == EViewAction.ProfilesFocus)
{
lstProfiles.Focus();
}
@@ -265,24 +278,8 @@ namespace v2rayN.Views
return;
}
//find index
var index = lstProfiles.Columns.IndexOf(colHeader.Column);
if (index < 0)
{
index = colHeader.TabIndex;
}
if (index == 0)
{
foreach (var it in lstProfiles.Columns)
{
//it.MinWidth = it.ActualWidth;
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
return;
}
ViewModel?.SortServer(index);
var colName = ((MyDGTextColumn)colHeader.Column).ExName;
ViewModel?.SortServer(colName);
}
private void menuSelectAll_Click(object sender, RoutedEventArgs e)
@@ -355,7 +352,7 @@ namespace v2rayN.Views
}
else
{
if (e.Key == Key.Enter || e.Key == Key.Return)
if (e.Key is Key.Enter or Key.Return)
{
ViewModel?.SetDefaultServer();
}
@@ -401,6 +398,26 @@ namespace v2rayN.Views
{
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
}
private void BtnAutofitColumnWidth_Click(object sender, RoutedEventArgs e)
{
AutofitColumnWidth();
}
private void AutofitColumnWidth()
{
foreach (var it in lstProfiles.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}
private void TxtServerFilter_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key is Key.Enter or Key.Return)
{
ViewModel?.RefreshServers();
}
}
#endregion
#region UI
@@ -413,27 +430,38 @@ namespace v2rayN.Views
Height = _config.uiItem.mainHeight;
}
IntPtr hWnd = new WindowInteropHelper(this).EnsureHandle();
Graphics g = Graphics.FromHwnd(hWnd);
if (Width > SystemInformation.WorkingArea.Width * 96 / g.DpiX)
{
Width = SystemInformation.WorkingArea.Width * 96 / g.DpiX;
}
if (Height > SystemInformation.WorkingArea.Height * 96 / g.DpiY)
{
Height = SystemInformation.WorkingArea.Height * 96 / g.DpiY;
}
var maxWidth = SystemParameters.WorkArea.Width;
var maxHeight = SystemParameters.WorkArea.Height;
if (Width > maxWidth) Width = maxWidth;
if (Height > maxHeight) Height = maxHeight;
if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0)
{
gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, 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));
lstProfiles.Columns[k].Width = width;
var item = lvColumnItem[i];
for (int k = 1; k < lstProfiles.Columns.Count; k++)
{
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
if (item2.ExName == item.Name)
{
if (item.Width < 0)
{
item2.Visibility = Visibility.Hidden;
}
else
{
item2.Width = item.Width;
item2.DisplayIndex = i;
}
}
}
}
if (!_config.guiItem.enableStatistics)
{
colTodayUp.Visibility = Visibility.Hidden;
@@ -447,10 +475,19 @@ namespace v2rayN.Views
_config.uiItem.mainWidth = this.Width;
_config.uiItem.mainHeight = this.Height;
List<ColumnItem> lvColumnItem = new();
for (int k = 0; 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 = item2.Visibility == Visibility.Visible ? Convert.ToInt32(item2.ActualWidth) : 0,
Index = item2.DisplayIndex
});
}
_config.uiItem.mainColumnItem = lvColumnItem;
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1);
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1);
}
@@ -471,9 +508,8 @@ namespace v2rayN.Views
}
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());
}
}
@@ -482,7 +518,7 @@ namespace v2rayN.Views
#endregion
#region Drag and Drop
private Point startPoint = new Point();
private Point startPoint = new();
private int startIndex = -1;
private string formatData = "ProfileItemModel";
@@ -523,8 +559,7 @@ namespace v2rayN.Views
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
// Get the dragged Item
var listView = sender as DataGrid;
if (listView == null) return;
if (sender is not DataGrid listView) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null) return; // Abort
// Find the data behind the ListViewItem
@@ -532,7 +567,7 @@ namespace v2rayN.Views
if (item == null) return; // Abort
// Initialize the drag & drop operation
startIndex = lstProfiles.SelectedIndex;
DataObject dragData = new DataObject(formatData, item);
DataObject dragData = new(formatData, item);
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
}
}
@@ -550,8 +585,7 @@ namespace v2rayN.Views
if (e.Data.GetDataPresent(formatData) && sender == e.Source)
{
// Get the drop Item destination
var listView = sender as DataGrid;
if (listView == null) return;
if (sender is not DataGrid listView) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null)
{

View File

@@ -48,6 +48,7 @@
FontSize="{DynamicResource StdFontSizeMsg}"
HorizontalScrollBarVisibility="Auto"
IsReadOnly="True"
IsReadOnlyCaretVisible="True"
TextAlignment="Left"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Visible">

View File

@@ -11,6 +11,10 @@ namespace v2rayN.Views
public partial class MsgView
{
private static Config _config;
private string lastMsgFilter;
private bool lastMsgFilterNotAvailable;
public MsgView()
{
InitializeComponent();
@@ -28,28 +32,38 @@ namespace v2rayN.Views
void DelegateAppendText(string msg)
{
Dispatcher.BeginInvoke(new Action<string>(AppendText), DispatcherPriority.Send, msg);
Dispatcher.BeginInvoke(AppendText, DispatcherPriority.Send, msg);
}
public void AppendText(string msg)
{
if (msg.Equals(Global.CommandClearMsg))
if (msg == Global.CommandClearMsg)
{
ClearMsg();
return;
}
if (!togAutoRefresh.IsChecked.Value)
if (togAutoRefresh.IsChecked == false)
{
return;
}
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
{
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);
}

View File

@@ -10,19 +10,20 @@
xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuSetting}"
Width="900"
Width="1000"
Height="700"
x:TypeArguments="vms:OptionSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel Margin="16">
<DockPanel Margin="8">
<Grid HorizontalAlignment="Center" DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
@@ -46,7 +47,7 @@
Style="{StaticResource DefButton}" />
</Grid>
<TabControl>
<TabControl HorizontalContentAlignment="Left">
<TabItem Header="{x:Static resx:ResUI.TbSettingsCore}">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<Grid Margin="{StaticResource SettingItemMargin}">
@@ -215,7 +216,7 @@
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" />
Text="{x:Static resx:ResUI.TbSettingsLogEnabledToFile}" />
<ToggleButton
x:Name="toglogEnabled"
Grid.Row="9"
@@ -480,11 +481,12 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
@@ -506,7 +508,8 @@
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}" />
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="2"
@@ -665,22 +668,6 @@
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="13"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsAutoUpdate}" />
<TextBox
x:Name="txtautoUpdateSubInterval"
Grid.Row="13"
Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="14"
Grid.Column="0"
@@ -718,7 +705,8 @@
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}" />
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="16"
@@ -749,6 +737,20 @@
Width="300"
Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="18"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsEnableHWA}" />
<ToggleButton
x:Name="togEnableHWA"
Grid.Row="18"
Grid.Column="1"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" />
</Grid>
</ScrollViewer>
</TabItem>
@@ -815,7 +817,7 @@
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="1"
Grid.Row="0"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
@@ -823,6 +825,20 @@
Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" />
<ToggleButton
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.Column="1"
Margin="{StaticResource SettingItemMargin}"
@@ -926,13 +942,15 @@
<Grid
x:Name="gridTunModeDirect"
Width="600"
Width="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
@@ -957,17 +975,31 @@
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</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
x:Name="gridTunModeProxy"
Width="600"
Width="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
@@ -992,6 +1024,18 @@
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</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>
</DockPanel>

View File

@@ -1,4 +1,5 @@
using ReactiveUI;
using Microsoft.Win32;
using ReactiveUI;
using System.Globalization;
using System.IO;
using System.Reactive.Disposables;
@@ -17,6 +18,7 @@ namespace v2rayN.Views
public OptionSettingWindow()
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = LazyConfig.Instance.GetConfig();
ViewModel = new OptionSettingViewModel(this);
@@ -75,13 +77,12 @@ namespace v2rayN.Views
//fill fonts
try
{
var dir = new DirectoryInfo(Utils.GetFontsPath());
var files = dir.GetFiles("*.ttf");
var culture = _config.uiItem.currentLanguage.Equals(Global.Languages[0]) ? "zh-cn" : "en-us";
var files = Directory.GetFiles(Utils.GetFontsPath(), "*.ttf");
var culture = _config.uiItem.currentLanguage == Global.Languages[0] ? "zh-cn" : "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)
{
var typefaces = family.GetTypefaces();
@@ -159,11 +160,11 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.EnableDragDropSort, v => v.togEnableDragDropSort.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.autoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.autoUpdateSubInterval, v => v.txtautoUpdateSubInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.trayMenuServersLimit, v => v.txttrayMenuServersLimit.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.currentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableHWA, v => v.togEnableHWA.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
@@ -171,6 +172,7 @@ namespace v2rayN.Views
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.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
@@ -180,8 +182,10 @@ namespace v2rayN.Views
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.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.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);
@@ -206,7 +210,7 @@ namespace v2rayN.Views
}
private void btnBrowse_Click(object sender, System.Windows.RoutedEventArgs e)
{
var openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
var openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "tunConfig|*.json|All|*.*";
openFileDialog1.ShowDialog();

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
@@ -133,7 +134,7 @@
</Grid>
<Grid
Margin="16"
Margin="8"
HorizontalAlignment="Center"
DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>

View File

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

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
@@ -31,28 +32,40 @@
Style="{StaticResource MaterialDesignToolBar}">
<Button x:Name="menuRuleAdd">
<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}" />
</StackPanel>
</Button>
<Separator />
<Button x:Name="menuImportRulesFromFile">
<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}" />
</StackPanel>
</Button>
<Separator />
<Button x:Name="menuImportRulesFromClipboard">
<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}" />
</StackPanel>
</Button>
<Separator />
<Button x:Name="menuImportRulesFromUrl">
<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}" />
</StackPanel>
</Button>
@@ -60,7 +73,7 @@
</ToolBarTray>
<Grid
Margin="16"
Margin="8"
HorizontalAlignment="Center"
DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>

View File

@@ -1,4 +1,5 @@
using ReactiveUI;
using Microsoft.Win32;
using ReactiveUI;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input;
@@ -12,6 +13,7 @@ namespace v2rayN.Views
public RoutingRuleSettingWindow(RoutingItem routingItem)
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded;
this.PreviewKeyDown += RoutingRuleSettingWindow_PreviewKeyDown;
lstRules.SelectionChanged += lstRules_SelectionChanged;
@@ -107,7 +109,7 @@ namespace v2rayN.Views
private void btnBrowse_Click(object sender, System.Windows.RoutedEventArgs e)
{
var openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
var openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "PNG|*.png";
openFileDialog1.ShowDialog();

View File

@@ -16,6 +16,7 @@
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
@@ -38,7 +39,10 @@
<MenuItem x:Name="menuRoutingBasic" Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -53,7 +57,10 @@
<MenuItem x:Name="menuRoutingAdvanced" Padding="8,0">
<MenuItem.Header>
<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}" />
</StackPanel>
</MenuItem.Header>
@@ -107,7 +114,7 @@
</ToolBarTray>
<Grid
Margin="16"
Margin="8"
HorizontalAlignment="Center"
DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
@@ -180,22 +187,22 @@
Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Resources>
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding isActive}" Value="True">
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryHueLightBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Width="50">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border
Width="auto"
Height="auto"
Background="{DynamicResource PrimaryHueLightBrush}"
Visibility="{Binding Path=isActive, Converter={StaticResource BoolToVisConverter}}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn
Width="200"
Binding="{Binding remarks}"
Header="{x:Static resx:ResUI.LvAlias}" />
Header="{x:Static resx:ResUI.LvRemarks}" />
<DataGridTextColumn
Width="60"
Binding="{Binding ruleNum}"

View File

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

View File

@@ -11,17 +11,26 @@
xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuSubSetting}"
Width="700"
Height="550"
Height="600"
x:TypeArguments="vms:SubEditViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<ScrollViewer
materialDesign:ScrollViewerAssist.IsAutoHideEnabled="True"
HorizontalScrollBarVisibility="Auto"
@@ -40,10 +49,12 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
@@ -91,6 +102,31 @@
Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="Wrap" />
<materialDesign:PopupBox
Grid.Row="2"
Grid.Column="2"
HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
<StackPanel>
<TextBlock
Margin="4"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.LvMoreUrl}" />
<TextBox
x:Name="txtMoreUrl"
Width="400"
Margin="4"
VerticalAlignment="Top"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
AcceptsReturn="True"
MinLines="4"
Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="Wrap" />
</StackPanel>
</materialDesign:PopupBox>
<TextBlock
Grid.Row="3"
Grid.Column="0"
@@ -110,10 +146,28 @@
Grid.Column="0"
Margin="4"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.LvAutoUpdateInterval}" />
<TextBox
x:Name="txtAutoUpdateInterval"
Grid.Row="4"
Grid.Column="1"
Width="400"
Margin="4"
VerticalAlignment="Top"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.SubUrlTips}"
AcceptsReturn="True"
Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="4"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.LvUserAgent}" />
<TextBox
x:Name="txtUserAgent"
Grid.Row="4"
Grid.Row="5"
Grid.Column="1"
Width="400"
Margin="4"
@@ -124,7 +178,7 @@
TextWrapping="Wrap" />
<TextBlock
Grid.Row="5"
Grid.Row="6"
Grid.Column="0"
Margin="4"
VerticalAlignment="Center"
@@ -132,7 +186,7 @@
Text="{x:Static resx:ResUI.LvFilter}" />
<TextBox
x:Name="txtFilter"
Grid.Row="5"
Grid.Row="6"
Grid.Column="1"
Width="400"
Margin="4"
@@ -142,7 +196,7 @@
Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock
Grid.Row="6"
Grid.Row="7"
Grid.Column="0"
Margin="4"
VerticalAlignment="Center"
@@ -150,7 +204,7 @@
Text="{x:Static resx:ResUI.LvSort}" />
<TextBox
x:Name="txtSort"
Grid.Row="6"
Grid.Row="7"
Grid.Column="1"
Width="400"
Margin="4"
@@ -161,7 +215,7 @@
</Grid>
<Grid
Grid.Row="1"
Margin="16"
Margin="8"
HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />

View File

@@ -11,6 +11,7 @@ namespace v2rayN.Views
public SubEditWindow(SubItem subItem)
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded;
ViewModel = new SubEditViewModel(subItem, this);
@@ -19,7 +20,9 @@ namespace v2rayN.Views
{
this.Bind(ViewModel, vm => vm.SelectedSource.remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.url, v => v.txtUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.moreUrl, v => v.txtMoreUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.enabled, v => v.togEnable.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.autoUpdateInterval, v => v.txtAutoUpdateInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.userAgent, v => v.txtUserAgent.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.sort, v => v.txtSort.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.filter, v => v.txtFilter.Text).DisposeWith(disposables);

View File

@@ -10,12 +10,13 @@
xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuSubSetting}"
Width="700"
Width="800"
Height="600"
x:TypeArguments="vms:SubSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display"
@@ -32,28 +33,40 @@
Style="{StaticResource MaterialDesignToolBar}">
<Button x:Name="menuSubAdd">
<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}" />
</StackPanel>
</Button>
<Separator />
<Button x:Name="menuSubDelete">
<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}" />
</StackPanel>
</Button>
<Separator />
<Button x:Name="menuSubEdit">
<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}" />
</StackPanel>
</Button>
<Separator />
<Button x:Name="menuSubShare">
<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}" />
</StackPanel>
</Button>
@@ -62,7 +75,10 @@
Click="menuClose_Click"
IsCancel="True">
<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}" />
</StackPanel>
</Button>
@@ -88,15 +104,19 @@
Binding="{Binding remarks}"
Header="{x:Static resx:ResUI.LvRemarks}" />
<DataGridTextColumn
Width="200"
Width="150"
Binding="{Binding url}"
Header="{x:Static resx:ResUI.LvUrl}" />
<DataGridTextColumn
Width="80"
Width="100"
Binding="{Binding enabled}"
Header="{x:Static resx:ResUI.LvEnabled}" />
<DataGridTextColumn
Width="200"
Width="150"
Binding="{Binding autoUpdateInterval}"
Header="{x:Static resx:ResUI.LvAutoUpdateInterval}" />
<DataGridTextColumn
Width="150"
Binding="{Binding userAgent}"
Header="{x:Static resx:ResUI.LvUserAgent}" />
<DataGridTextColumn

View File

@@ -1,7 +1,9 @@
using ReactiveUI;
using System.ComponentModel;
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input;
using v2rayN.Mode;
using v2rayN.ViewModels;
namespace v2rayN.Views
@@ -11,10 +13,12 @@ namespace v2rayN.Views
public SubSettingWindow()
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
ViewModel = new SubSettingViewModel(this);
this.Closing += SubSettingWindow_Closing;
lstSubscription.MouseDoubleClick += LstSubscription_MouseDoubleClick;
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
this.WhenActivated(disposables =>
{
@@ -41,6 +45,10 @@ namespace v2rayN.Views
{
ViewModel?.EditSub(false);
}
private void LstSubscription_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
}
private void menuClose_Click(object sender, System.Windows.RoutedEventArgs e)
{

View File

@@ -6,4 +6,18 @@
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
@@ -9,20 +10,18 @@
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationIcon>v2rayN.ico</ApplicationIcon>
<Copyright>Copyright © 2017-2023 (GPLv3)</Copyright>
<FileVersion>6.10</FileVersion>
<FileVersion>6.22</FileVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Downloader" Version="3.0.3" />
<PackageReference Include="Downloader" Version="3.0.4" />
<PackageReference Include="MaterialDesignThemes" Version="4.7.1" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NHotkey" Version="2.1.0" />
<PackageReference Include="NHotkey.Wpf" Version="2.1.0" />
<PackageReference Include="H.NotifyIcon.Wpf" Version="2.0.108" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="QRCoder.Xaml" Version="1.4.3" />
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.10" />
<PackageReference Include="ZXing.Net.Bindings.Windows.Compatibility" Version="0.16.12" />
<PackageReference Include="ReactiveUI.Fody" Version="18.4.1" />
<PackageReference Include="ReactiveUI.Validation" Version="3.0.22" />
<PackageReference Include="ReactiveUI.WPF" Version="18.4.1" />
@@ -35,6 +34,9 @@
<EmbeddedResource Include="Sample\tun_singbox">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Sample\tun_singbox_dns">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Sample\custom_routing_black">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>

View File

@@ -11,18 +11,22 @@ namespace v2rayUpgrade
public partial class MainForm : Form
{
private readonly string defaultFilename = "v2ray-windows.zip";
private string fileName;
private string? fileName;
public MainForm(string[] args)
{
InitializeComponent();
if (args.Length > 0)
{
fileName = string.Join(" ", args);
fileName = HttpUtility.UrlDecode(fileName);
fileName = HttpUtility.UrlDecode(string.Join(" ", args));
}
else
{
fileName = defaultFilename;
}
}
private void showWarn(string message)
private void ShowWarn(string message)
{
MessageBox.Show(message, "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
@@ -34,7 +38,7 @@ namespace v2rayUpgrade
Process[] existing = Process.GetProcessesByName("v2rayN");
foreach (Process p in existing)
{
string path = p.MainModule.FileName;
string? path = p.MainModule?.FileName;
if (path == GetPath("v2rayN.exe"))
{
p.Kill();
@@ -45,13 +49,10 @@ namespace v2rayUpgrade
catch (Exception ex)
{
// 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);
}
StringBuilder sb = new StringBuilder();
try
{
if (!File.Exists(fileName))
{
if (File.Exists(defaultFilename))
@@ -60,18 +61,19 @@ namespace v2rayUpgrade
}
else
{
showWarn("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
ShowWarn("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
return;
}
}
string thisAppOldFile = Application.ExecutablePath + ".tmp";
StringBuilder sb = new();
try
{
string thisAppOldFile = $"{Application.ExecutablePath}.tmp";
File.Delete(thisAppOldFile);
string startKey = "v2rayN/";
using (ZipArchive archive = ZipFile.OpenRead(fileName))
{
using ZipArchive archive = ZipFile.OpenRead(fileName);
foreach (ZipArchiveEntry entry in archive.Entries)
{
try
@@ -83,17 +85,15 @@ namespace v2rayUpgrade
string fullName = entry.FullName;
if (fullName.StartsWith(startKey))
{
fullName = fullName.Substring(startKey.Length, fullName.Length - startKey.Length);
fullName = fullName[startKey.Length..];
}
if (Application.ExecutablePath.ToLower() == GetPath(fullName).ToLower())
if (string.Equals(Application.ExecutablePath, GetPath(fullName), StringComparison.OrdinalIgnoreCase))
{
File.Move(Application.ExecutablePath, thisAppOldFile);
}
string entryOuputPath = GetPath(fullName);
FileInfo fileInfo = new FileInfo(entryOuputPath);
fileInfo.Directory.Create();
Directory.CreateDirectory(Path.GetDirectoryName(entryOuputPath)!);
entry.ExtractToFile(entryOuputPath, true);
}
catch (Exception ex)
@@ -102,15 +102,14 @@ namespace v2rayUpgrade
}
}
}
}
catch (Exception ex)
{
showWarn("Upgrade Failed(升级失败)." + ex.StackTrace);
ShowWarn("Upgrade Failed(升级失败)." + ex.StackTrace);
return;
}
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());
return;
}

View File

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