Compare commits

...

194 Commits
6.8 ... 6.23

Author SHA1 Message Date
2dust
f612ce5db8 up 6.23 2023-04-21 15:55:05 +08:00
2dust
831a20ff91 Code clean 2023-04-21 15:15:35 +08:00
2dust
38ae669070 bug fixes for ErrorDataReceived 2023-04-21 14:49:33 +08:00
2dust
fed7e7764e bug fixes 2023-04-21 14:09:55 +08:00
2dust
f3804fce40 Add subscription conversion
https://github.com/tindy2013/subconverter/blob/master/README-cn.md
2023-04-21 12:15:24 +08:00
2dust
88e7cd09d7 The skip delay is -1 speed test in multi-threaded test 2023-04-21 12:11:09 +08:00
2dust
1ce5571ac6 Hide tray tip text 2023-04-21 10:32:41 +08:00
2dust
355bf84af4 bug fixes 2023-04-19 16:33:08 +08:00
2dust
6e8a3a4867 Code clean 2023-04-16 20:45:47 +08:00
2dust
bf6dcdf2bd Code clean 2023-04-14 20:49:36 +08:00
2dust
165454dc57 Migrate from Grpc.Core to Grpc.Net.Client 2023-04-14 15:51:34 +08:00
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
2dust
82f236e07b up 6.10 2023-02-11 20:03:54 +08:00
2dust
17bfe74ecf Add routing sort 2023-02-11 19:34:15 +08:00
2dust
b77827df90 Update v2rayN.csproj 2023-02-10 21:02:41 +08:00
2dust
a359a508ae fix Import old config 2023-02-10 21:02:29 +08:00
2dust
3a740118f0 Adjust task service settings 2023-02-10 18:58:20 +08:00
2dust
58d9bcbd14 tidy code github 2023-02-10 16:25:16 +08:00
2dust
24be7b2180 store msg filter 2023-02-10 16:01:47 +08:00
2dust
f4c9ca8dff Refactor routing basic settings 2023-02-10 14:51:00 +08:00
2dust
9b8181b72b Refactor gui settings 2023-02-10 14:36:37 +08:00
2dust
1ff1962425 Refactor basic settings 2023-02-10 14:16:59 +08:00
2dust
9b05736746 Add environment variables to geo files 2023-02-10 11:22:03 +08:00
2dust
dec722e693 Update UpdateHandle.cs 2023-02-10 11:05:11 +08:00
2dust
49fa0a4c67 DownloadStringAsyncOri 2023-02-10 11:04:57 +08:00
2dust
0cdc69e1e8 Update MsgView.xaml 2023-02-10 09:39:18 +08:00
2dust
0494cc4ce7 adjust group style 2023-02-09 16:43:50 +08:00
2dust
30d82947d6 fix 2023-02-09 15:17:52 +08:00
2dust
ec59249d79 Optimize file download 2023-02-09 14:54:54 +08:00
2dust
7eb869ab1d Optimize file download 2023-02-09 10:54:31 +08:00
2dust
d014724a2d Optimize speed test 2023-02-08 19:20:44 +08:00
2dust
dfb6cef364 Update OptionSettingWindow.xaml.cs 2023-02-08 15:07:23 +08:00
2dust
0ebf8c9349 Optimize Font size 2023-02-07 19:05:49 +08:00
2dust
9dfd89c90d up 6.9 2023-02-06 19:28:43 +08:00
2dust
f6972125cd Update tun_singbox 2023-02-06 19:19:36 +08:00
2dust
6e366bf55a Improved enhanced tun mode 2023-02-06 15:29:10 +08:00
2dust
5e2e45c673 Merge branch 'master' of https://github.com/2dust/v2rayN 2023-02-05 20:17:07 +08:00
2dust
f879235564 fix get Win32FamilyNames 2023-02-05 20:17:03 +08:00
2dust
b00aee2ae7 Merge pull request #3187 from saphirique/patch-1
Add russian language
2023-02-05 19:57:08 +08:00
saphirique
28c2159ec3 add russian language 2023-02-05 17:55:24 +08:00
2dust
33dcef2285 Optimize Update Subscription 2023-02-04 18:52:17 +08:00
2dust
b9acd0ec28 Font size custom 2023-02-04 15:43:49 +08:00
2dust
7989d5180b adjust style 2023-02-04 14:25:21 +08:00
2dust
238086942e change fonts folder 2023-02-04 12:50:38 +08:00
115 changed files with 6221 additions and 3393 deletions

1
.gitignore vendored
View File

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

View File

@@ -1,5 +1,5 @@
# v2rayN # 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) [![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) [![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) [![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) ## How to use
- Otherwise please download v2rayN.zip (you will also need to download v2ray core into the same folder with v2rayN.exe) - 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 - Run v2rayN.exe
### Requirements ## Requirements
- Microsoft [.NET Framework 4.8 Runtime](https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net48-offline-installer) - [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)
- v2fly core [https://github.com/v2fly/v2ray-core/releases](https://github.com/v2fly/v2ray-core/releases) - [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
- Xray core [https://github.com/XTLS/Xray-core/releases](https://github.com/XTLS/Xray-core/releases)
### Telegram Channel
## Telegram Channel
[github_2dust](https://t.me/github_2dust) [github_2dust](https://t.me/github_2dust)

View File

@@ -17,16 +17,9 @@ public class PacHandler
private static bool _isRunning; private static bool _isRunning;
private static bool _needRestart = true; private static bool _needRestart = true;
public static void Start(string configPath, int httpPort, int pacPort) public static void Start(string configPath, int httpPort, int pacPort)
{ {
if (configPath.Equals(_configPath) _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
&& httpPort.Equals(_httpPort)
&& pacPort.Equals(_pacPort)
&& _isRunning)
{
_needRestart = false;
}
_configPath = configPath; _configPath = configPath;
_httpPort = httpPort; _httpPort = httpPort;
@@ -89,9 +82,7 @@ public class PacHandler
{ {
} }
} }
}, TaskCreationOptions.LongRunning); }, TaskCreationOptions.LongRunning);
} }
public static void Stop() public static void Stop()

View File

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

View File

@@ -8,8 +8,6 @@ namespace ProtosLib
public Tests() public Tests()
{ {
} }
} }
} }

View File

@@ -1,10 +1,9 @@
<Application <Application
x:Class="v2rayN.App" x:Class="v2rayN.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters" xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:local="clr-namespace:v2rayN"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
ShutdownMode="OnExplicitShutdown" ShutdownMode="OnExplicitShutdown"
StartupUri="Views/MainWindow.xaml"> StartupUri="Views/MainWindow.xaml">
<Application.Resources> <Application.Resources>
@@ -17,6 +16,10 @@
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<system:Double x:Key="MenuItemHeight">26</system:Double> <system:Double x:Key="MenuItemHeight">26</system:Double>
<system:Double x:Key="StdFontSize">12</system:Double>
<system:Double x:Key="StdFontSize1">13</system:Double>
<system:Double x:Key="StdFontSize2">14</system:Double>
<system:Double x:Key="StdFontSizeMsg">11</system:Double>
<Thickness <Thickness
x:Key="ServerItemMargin" x:Key="ServerItemMargin"
Bottom="4" Bottom="4"
@@ -33,19 +36,19 @@
x:Key="ModuleTitle" x:Key="ModuleTitle"
BasedOn="{StaticResource MaterialDesignTextBlock}" BasedOn="{StaticResource MaterialDesignTextBlock}"
TargetType="{x:Type TextBlock}"> TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="16" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize2}" />
</Style> </Style>
<Style <Style
x:Key="ToolbarTextBlock" x:Key="ToolbarTextBlock"
BasedOn="{StaticResource MaterialDesignTextBlock}" BasedOn="{StaticResource MaterialDesignTextBlock}"
TargetType="{x:Type TextBlock}"> TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style> </Style>
<Style <Style
x:Key="StatusbarItem" x:Key="StatusbarItem"
BasedOn="{StaticResource MaterialDesignTextBlock}" BasedOn="{StaticResource MaterialDesignTextBlock}"
TargetType="{x:Type TextBlock}"> TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Setter Property="Padding" Value="0" /> <Setter Property="Padding" Value="0" />
</Style> </Style>
<Style TargetType="{x:Type TextElement}"> <Style TargetType="{x:Type TextElement}">
@@ -58,7 +61,7 @@
</Style> </Style>
<Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}"> <Style x:Key="lvItemSelected" TargetType="{x:Type ListViewItem}">
<Setter Property="Height" Value="20" /> <Setter Property="Height" Value="20" />
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Style.Triggers> <Style.Triggers>
<Trigger Property="IsSelected" Value="true"> <Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" /> <Setter Property="Background" Value="{DynamicResource PrimaryHueLightBrush}" />
@@ -76,22 +79,19 @@
x:Key="ListItemCheckBox" x:Key="ListItemCheckBox"
BasedOn="{StaticResource MaterialDesignUserForegroundCheckBox}" BasedOn="{StaticResource MaterialDesignUserForegroundCheckBox}"
TargetType="{x:Type CheckBox}"> TargetType="{x:Type CheckBox}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style>
<Style x:Key="ListItemChip" TargetType="{x:Type materialDesign:Chip}">
<Setter Property="FontSize" Value="11" />
</Style> </Style>
<Style <Style
x:Key="DefButton" x:Key="DefButton"
BasedOn="{StaticResource MaterialDesignRaisedButton}" BasedOn="{StaticResource MaterialDesignRaisedButton}"
TargetType="{x:Type ButtonBase}"> TargetType="{x:Type ButtonBase}">
<Setter Property="FontSize" Value="14" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
</Style> </Style>
<Style <Style
x:Key="DefContextMenu" x:Key="DefContextMenu"
BasedOn="{StaticResource MaterialDesignContextMenu}" BasedOn="{StaticResource MaterialDesignContextMenu}"
TargetType="{x:Type ContextMenu}"> TargetType="{x:Type ContextMenu}">
<Setter Property="FontSize" Value="13" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" /> <Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
</Style> </Style>
@@ -99,7 +99,7 @@
x:Key="ToolbarMenu" x:Key="ToolbarMenu"
BasedOn="{StaticResource MaterialDesignMenu}" BasedOn="{StaticResource MaterialDesignMenu}"
TargetType="{x:Type Menu}"> TargetType="{x:Type Menu}">
<Setter Property="FontSize" Value="13" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize1}" />
<Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" /> <Setter Property="FontFamily" Value="{x:Static conv:MaterialDesignFonts.MyFont}" />
</Style> </Style>
@@ -107,17 +107,39 @@
x:Key="DefComboBox" x:Key="DefComboBox"
BasedOn="{StaticResource MaterialDesignComboBox}" BasedOn="{StaticResource MaterialDesignComboBox}"
TargetType="{x:Type ComboBox}"> TargetType="{x:Type ComboBox}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
<Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="HorizontalAlignment" Value="Left" />
</Style> </Style>
<Style <Style
x:Key="DefDataGrid" x:Key="DefDataGrid"
BasedOn="{StaticResource MaterialDesignDataGrid}" BasedOn="{StaticResource MaterialDesignDataGrid}"
TargetType="{x:Type DataGrid}"> TargetType="{x:Type DataGrid}">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style>
<Style
x:Key="DefTextBox"
BasedOn="{StaticResource MaterialDesignTextBox}"
TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style>
<Style
x:Key="MyOutlinedTextBox"
BasedOn="{StaticResource MaterialDesignOutlinedTextBox}"
TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style>
<Style
x:Key="MyGroupBox"
BasedOn="{StaticResource MaterialDesignGroupBox}"
TargetType="{x:Type GroupBox}">
<Setter Property="FontSize" Value="{DynamicResource StdFontSize}" />
</Style>
<Style
x:Key="MyChipListBoxItem"
BasedOn="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBoxItem}"
TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="-2,0" />
</Style> </Style>
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>
</Application>
</Application>

View File

@@ -30,8 +30,9 @@ namespace v2rayN
{ {
Global.ExePathKey = Utils.GetMD5(Utils.GetExePath()); 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); ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, Global.ExePathKey, out bool bCreatedNew);
if (!bCreatedNew) if (!rebootas && !bCreatedNew)
{ {
ProgramStarted.Set(); ProgramStarted.Set();
Current.Shutdown(); Current.Shutdown();
@@ -42,17 +43,16 @@ namespace v2rayN
Global.processJob = new Job(); Global.processJob = new Job();
Logging.Setup(); Logging.Setup();
Init();
Logging.LoggingEnabled(_config.guiItem.enableLog);
Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}"); Utils.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
Logging.ClearLogs(); Logging.ClearLogs();
Init();
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage); Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
base.OnStartup(e); base.OnStartup(e);
} }
private void Init() private void Init()
{ {
if (ConfigHandler.LoadConfig(ref _config) != 0) if (ConfigHandler.LoadConfig(ref _config) != 0)
@@ -62,7 +62,12 @@ namespace v2rayN
Environment.Exit(0); Environment.Exit(0);
return; return;
} }
//if (RuntimeInformation.ProcessArchitecture != Architecture.X86 && RuntimeInformation.ProcessArchitecture != Architecture.X64)
//{
// _config.guiItem.enableStatistics = false;
//}
} }
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{ {
Utils.SaveLog("App_DispatcherUnhandledException", e.Exception); Utils.SaveLog("App_DispatcherUnhandledException", e.Exception);
@@ -77,9 +82,9 @@ namespace v2rayN
} }
} }
private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
{ {
Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception); Utils.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
} }
} }
} }

View File

@@ -7,4 +7,4 @@ using System.Windows;
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page, //(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries) // app, or any theme specific resource dictionaries)
)] )]

View File

@@ -0,0 +1,186 @@
using Downloader;
using System.IO;
using System.Net;
namespace v2rayN.Base
{
internal class DownloaderHelper
{
private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
public static DownloaderHelper Instance => _instance.Value;
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
{
if (string.IsNullOrEmpty(url))
{
return null;
}
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000);
Uri uri = new(url);
//Authorization Header
var headers = new WebHeaderCollection();
if (!Utils.IsNullOrEmpty(uri.UserInfo))
{
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
}
var downloadOpt = new DownloadConfiguration()
{
Timeout = timeout * 1000,
MaxTryAgainOnFailover = 2,
RequestConfiguration =
{
Headers = headers,
UserAgent = userAgent,
Timeout = timeout * 1000,
Proxy = webProxy
}
};
using var downloader = new DownloadService(downloadOpt);
downloader.DownloadFileCompleted += (sender, value) =>
{
if (value.Error != null)
{
throw value.Error;
}
};
using var stream = await downloader.DownloadFileTaskAsync(address: url, cancellationToken: cancellationToken.Token);
using StreamReader reader = new(stream);
downloadOpt = null;
return reader.ReadToEnd();
}
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException(nameof(url));
}
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000);
var downloadOpt = new DownloadConfiguration()
{
Timeout = timeout * 1000,
MaxTryAgainOnFailover = 2,
RequestConfiguration =
{
Timeout= timeout * 1000,
Proxy = webProxy
}
};
DateTime totalDatetime = DateTime.Now;
int totalSecond = 0;
var hasValue = false;
double maxSpeed = 0;
using var downloader = new DownloadService(downloadOpt);
//downloader.DownloadStarted += (sender, value) =>
//{
// if (progress != null)
// {
// progress.Report("Start download data...");
// }
//};
downloader.DownloadProgressChanged += (sender, value) =>
{
TimeSpan ts = (DateTime.Now - totalDatetime);
if (progress != null && ts.Seconds > totalSecond)
{
hasValue = true;
totalSecond = ts.Seconds;
if (value.BytesPerSecondSpeed > maxSpeed)
{
maxSpeed = value.BytesPerSecondSpeed;
var speed = (maxSpeed / 1000 / 1000).ToString("#0.0");
progress.Report(speed);
}
}
};
downloader.DownloadFileCompleted += (sender, value) =>
{
if (progress != null)
{
if (!hasValue && value.Error != null)
{
progress.Report(value.Error?.Message);
}
}
};
//progress.Report("......");
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)
{
if (string.IsNullOrEmpty(url))
{
throw new ArgumentNullException(nameof(url));
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException(nameof(fileName));
}
if (File.Exists(fileName))
{
File.Delete(fileName);
}
var cancellationToken = new CancellationTokenSource();
cancellationToken.CancelAfter(timeout * 1000);
var downloadOpt = new DownloadConfiguration()
{
Timeout = timeout * 1000,
MaxTryAgainOnFailover = 2,
RequestConfiguration =
{
Timeout= timeout * 1000,
Proxy = webProxy
}
};
var progressPercentage = 0;
var hasValue = false;
using var downloader = new DownloadService(downloadOpt);
downloader.DownloadStarted += (sender, value) =>
{
progress?.Report(0);
};
downloader.DownloadProgressChanged += (sender, value) =>
{
hasValue = true;
var percent = (int)value.ProgressPercentage;// Convert.ToInt32((totalRead * 1d) / (total * 1d) * 100);
if (progressPercentage != percent && percent % 10 == 0)
{
progressPercentage = percent;
progress.Report(percent);
}
};
downloader.DownloadFileCompleted += (sender, value) =>
{
if (progress != null)
{
if (hasValue && value.Error == null)
{
progress.Report(101);
}
}
};
await downloader.DownloadFileTaskAsync(url, fileName, cancellationToken: cancellationToken.Token);
downloadOpt = null;
}
}
}

View File

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

View File

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

View File

@@ -1,16 +1,16 @@
 using SQLite;
using SQLite;
using System.Collections; using System.Collections;
namespace v2rayN.Base namespace v2rayN.Base
{ {
public sealed class SqliteHelper public sealed class SqliteHelper
{ {
private static readonly Lazy<SqliteHelper> _instance = new Lazy<SqliteHelper>(() => new()); private static readonly Lazy<SqliteHelper> _instance = new(() => new());
public static SqliteHelper Instance => _instance.Value; public static SqliteHelper Instance => _instance.Value;
private string _connstr; private string _connstr;
public SQLiteConnection _db; private SQLiteConnection _db;
public SQLiteAsyncConnection _dbAsync; private SQLiteAsyncConnection _dbAsync;
private static readonly object objLock = new();
public SqliteHelper() public SqliteHelper()
{ {
@@ -24,18 +24,32 @@ namespace v2rayN.Base
return _db.CreateTable<T>(); return _db.CreateTable<T>();
} }
public int Add(object model) public int Insert(object model)
{ {
return _db.Insert(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); return await _dbAsync.InsertAsync(model);
} }
public int Replace(object model) public int Replace(object model)
{ {
return _db.InsertOrReplace(model); lock (objLock)
{
return _db.InsertOrReplace(model);
}
} }
public async Task<int> Replacesync(object model) public async Task<int> Replacesync(object model)
{ {
return await _dbAsync.InsertOrReplaceAsync(model); return await _dbAsync.InsertOrReplaceAsync(model);
@@ -43,37 +57,53 @@ namespace v2rayN.Base
public int Update(object model) public int Update(object model)
{ {
return _db.Update(model); lock (objLock)
{
return _db.Update(model);
}
} }
public async Task<int> UpdateAsync(object model) public async Task<int> UpdateAsync(object model)
{ {
return await _dbAsync.UpdateAsync(model); return await _dbAsync.UpdateAsync(model);
} }
public int UpdateAll(IEnumerable models) public int UpdateAll(IEnumerable models)
{ {
return _db.UpdateAll(models); lock (objLock)
{
return _db.UpdateAll(models);
}
} }
public int Delete(object model) public int Delete(object model)
{ {
return _db.Delete(model); lock (objLock)
{
return _db.Delete(model);
}
} }
public async Task<int> DeleteAsync(object model) public async Task<int> DeleteAsync(object model)
{ {
return await _dbAsync.DeleteAsync(model); return await _dbAsync.DeleteAsync(model);
} }
public List<T> Query<T>(string sql) where T : new() public List<T> Query<T>(string sql) where T : new()
{ {
return _db.Query<T>(sql); return _db.Query<T>(sql);
} }
public async Task<List<T>> QueryAsync<T>(string sql) where T : new() public async Task<List<T>> QueryAsync<T>(string sql) where T : new()
{ {
return await _dbAsync.QueryAsync<T>(sql); return await _dbAsync.QueryAsync<T>(sql);
} }
public int Execute(string sql) public int Execute(string sql)
{ {
return _db.Execute(sql); return _db.Execute(sql);
} }
public async Task<int> ExecuteAsync(string sql) public async Task<int> ExecuteAsync(string sql)
{ {
return await _dbAsync.ExecuteAsync(sql); return await _dbAsync.ExecuteAsync(sql);
@@ -83,6 +113,7 @@ namespace v2rayN.Base
{ {
return _db.Table<T>(); return _db.Table<T>();
} }
public AsyncTableQuery<T> TableAsync<T>() where T : new() public AsyncTableQuery<T> TableAsync<T>() where T : new()
{ {
return _dbAsync.Table<T>(); return _dbAsync.Table<T>();

View File

@@ -1,15 +1,16 @@
using System.IO; using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace v2rayN.Base namespace v2rayN.Base
{ {
static class StringEx internal static class StringEx
{ {
public static bool IsNullOrEmpty(this string value) public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{ {
return string.IsNullOrEmpty(value); return string.IsNullOrEmpty(value);
} }
public static bool IsNullOrWhiteSpace(this string value) public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
{ {
return string.IsNullOrWhiteSpace(value); return string.IsNullOrWhiteSpace(value);
} }
@@ -31,10 +32,9 @@ namespace v2rayN.Base
return true; return true;
} }
public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader) public static IEnumerable<string> NonWhiteSpaceLines(this TextReader reader)
{ {
string line; string? line;
while ((line = reader.ReadLine()) != null) while ((line = reader.ReadLine()) != null)
{ {
if (line.IsWhiteSpace()) continue; if (line.IsWhiteSpace()) continue;
@@ -42,9 +42,9 @@ namespace v2rayN.Base
} }
} }
public static string TrimEx(this string value) public static string TrimEx(this string? value)
{ {
return value == null ? string.Empty : value.Trim(); return value == null ? string.Empty : value.Trim();
} }
} }
} }

View File

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

View File

@@ -1,5 +1,4 @@
using System.IO; using System.Windows.Media;
using System.Windows.Media;
using v2rayN.Handler; using v2rayN.Handler;
namespace v2rayN.Converters namespace v2rayN.Converters
@@ -15,17 +14,14 @@ namespace v2rayN.Converters
var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily; var fontFamily = LazyConfig.Instance.GetConfig().uiItem.currentFontFamily;
if (!string.IsNullOrEmpty(fontFamily)) if (!string.IsNullOrEmpty(fontFamily))
{ {
var fontPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\Fonts\"); var fontPath = Utils.GetFontsPath();
MyFont = new FontFamily(new Uri($"file:///{fontPath}"), $"./#{fontFamily}"); MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");
} }
} }
catch catch
{ {
} }
if (MyFont is null) MyFont ??= new FontFamily("Microsoft YaHei");
{
MyFont = new FontFamily("Microsoft YaHei");
}
} }
} }
} }

View File

@@ -1,8 +1,11 @@
namespace v2rayN namespace v2rayN
{ {
class Global internal class Global
{ {
#region const #region const
public const string githubUrl = "https://github.com";
public const string githubApiUrl = "https://api.github.com/repos";
public const string v2rayWebsiteUrl = @"https://www.v2fly.org/"; public const string v2rayWebsiteUrl = @"https://www.v2fly.org/";
public const string AboutUrl = @"https://github.com/2dust/v2rayN"; public const string AboutUrl = @"https://github.com/2dust/v2rayN";
public const string UpdateUrl = AboutUrl + @"/releases"; public const string UpdateUrl = AboutUrl + @"/releases";
@@ -17,7 +20,6 @@
public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/releases"; public const string tuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
public const string singboxCoreUrl = "https://github.com/SagerNet/sing-box/releases"; public const string singboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
public const string geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat"; public const string geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
public const string SpeedTestUrl = @"http://cachefly.cachefly.net/10mb.test";
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204"; public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"; public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
@@ -32,6 +34,7 @@
public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_"; public const string CustomRoutingFileName = "v2rayN.Sample.custom_routing_";
public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound"; public const string v2raySampleInbound = "v2rayN.Sample.SampleInbound";
public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox"; public const string TunSingboxFileName = "v2rayN.Sample.tun_singbox";
public const string TunSingboxDNSFileName = "v2rayN.Sample.tun_singbox_dns";
public const string DefaultSecurity = "auto"; public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp"; public const string DefaultNetwork = "tcp";
@@ -41,7 +44,7 @@
public const string directTag = "direct"; public const string directTag = "direct";
public const string blockTag = "block"; public const string blockTag = "block";
public const string StreamSecurity = "tls"; public const string StreamSecurity = "tls";
public const string StreamSecurityX = "xtls"; public const string StreamSecurityReality = "reality";
public const string InboundSocks = "socks"; public const string InboundSocks = "socks";
public const string InboundHttp = "http"; public const string InboundHttp = "http";
public const string InboundSocks2 = "socks2"; public const string InboundSocks2 = "socks2";
@@ -77,27 +80,42 @@
public const string CommandClearMsg = "CommandClearMsg"; public const string CommandClearMsg = "CommandClearMsg";
public const string DelayUnit = ""; public const string DelayUnit = "";
public const string SpeedUnit = ""; 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}", "{ip}:{http_port}",
"socks={ip}:{socks_port}", "socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}", "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}", "http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
"" ""
}; };
public static readonly List<string> vmessSecuritys = new List<string> { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
public static readonly List<string> ssSecuritys = new List<string> { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" }; public static readonly List<string> SubConvertUrls = new List<string> {
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" }; @"https://sub.xeton.dev/sub?url={0}",
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" }; @"https://api.dler.io/sub?url={0}",
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" }; @"http://127.0.0.1:25500/sub?url={0}",
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> SubConvertConfig = new List<string> {
public static readonly List<string> domainMatchers = new List<string> { "linear", "mph", "" }; @"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
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> SubConvertTargets = new List<string> {
"",
"mixed",
"v2ray",
"clash",
"ss",
};
public static readonly List<string> SpeedTestUrls = new() {
@"http://cachefly.cachefly.net/100mb.test",
@"http://cachefly.cachefly.net/10mb.test"
};
public static readonly Dictionary<string, string> userAgentTxt = new()
{ {
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" }, {"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" }, {"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
@@ -105,28 +123,41 @@
{"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" }, {"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" },
{"none",""} {"none",""}
}; };
public static readonly List<string> allowInsecures = new List<string> { "true", "false", "" };
public static readonly List<string> domainStrategy4Freedoms = new List<string> { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
public static readonly List<string> Languages = new List<string> { "zh-Hans", "en", "fa-Ir" };
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).*$", "" };
#endregion 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> coreTypes4VLESS = new() { "Xray" };
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 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", "" };
#endregion const
#region global variable #region global variable
public static bool reloadCore { get; set; }
public static int statePort { get; set; } public static int statePort { get; set; }
public static Job processJob { get; set; } public static Job processJob { get; set; }
public static bool ShowInTaskbar { get; set; } public static bool ShowInTaskbar { get; set; }
public static string ExePathKey { get; set; } public static string ExePathKey { get; set; }
#endregion #endregion global variable
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ namespace v2rayN.Handler
/// <summary> /// <summary>
/// Core configuration file processing class /// Core configuration file processing class
/// </summary> /// </summary>
class CoreConfigHandler internal class CoreConfigHandler
{ {
private static string SampleClient = Global.v2raySampleClient; private static string SampleClient = Global.v2raySampleClient;
private static string SampleServer = Global.v2raySampleServer; private static string SampleServer = Global.v2raySampleServer;
@@ -25,7 +25,7 @@ namespace v2rayN.Handler
/// <param name="msg"></param> /// <param name="msg"></param>
/// <param name="content"></param> /// <param name="content"></param>
/// <returns></returns> /// <returns></returns>
public static int GenerateClientConfig(ProfileItem node, string fileName, out string msg, out string content) public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
{ {
content = string.Empty; content = string.Empty;
try try
@@ -43,7 +43,7 @@ namespace v2rayN.Handler
} }
else else
{ {
V2rayConfig v2rayConfig = null; V2rayConfig? v2rayConfig = null;
if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0) if (GenerateClientConfigContent(node, false, ref v2rayConfig, out msg) != 0)
{ {
return -1; return -1;
@@ -73,28 +73,29 @@ namespace v2rayN.Handler
{ {
if (blExport) if (blExport)
{ {
if (config.logEnabled) if (config.coreBasicItem.logEnabled)
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
} }
else else
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = "";
v2rayConfig.log.error = ""; v2rayConfig.log.error = "";
} }
} }
else else
{ {
if (config.logEnabled) if (config.coreBasicItem.logEnabled)
{ {
v2rayConfig.log.loglevel = config.loglevel; var dtNow = DateTime.Now;
v2rayConfig.log.access = Utils.GetLogPath(v2rayConfig.log.access); v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.error = Utils.GetLogPath(v2rayConfig.log.error); v2rayConfig.log.access = Utils.GetLogPath($"Vaccess_{dtNow:yyyy-MM-dd}.txt");
v2rayConfig.log.error = Utils.GetLogPath($"Verror_{dtNow:yyyy-MM-dd}.txt");
} }
else else
{ {
v2rayConfig.log.loglevel = config.loglevel; v2rayConfig.log.loglevel = config.coreBasicItem.loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = "";
v2rayConfig.log.error = ""; v2rayConfig.log.error = "";
} }
@@ -113,11 +114,11 @@ namespace v2rayN.Handler
{ {
v2rayConfig.inbounds = new List<Inbounds>(); v2rayConfig.inbounds = new List<Inbounds>();
Inbounds inbound = GetInbound(config.inbound[0], Global.InboundSocks, 0, true); Inbounds? inbound = GetInbound(config.inbound[0], Global.InboundSocks, 0, true);
v2rayConfig.inbounds.Add(inbound); v2rayConfig.inbounds.Add(inbound);
//http //http
Inbounds inbound2 = GetInbound(config.inbound[0], Global.InboundHttp, 1, false); Inbounds? inbound2 = GetInbound(config.inbound[0], Global.InboundHttp, 1, false);
v2rayConfig.inbounds.Add(inbound2); v2rayConfig.inbounds.Add(inbound2);
if (config.inbound[0].allowLANConn) if (config.inbound[0].allowLANConn)
@@ -156,7 +157,7 @@ namespace v2rayN.Handler
return 0; return 0;
} }
private static Inbounds GetInbound(InItem inItem, string tag, int offset, bool bSocks) private static Inbounds? GetInbound(InItem inItem, string tag, int offset, bool bSocks)
{ {
string result = Utils.GetEmbedText(Global.v2raySampleInbound); string result = Utils.GetEmbedText(Global.v2raySampleInbound);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
@@ -183,13 +184,12 @@ namespace v2rayN.Handler
{ {
try try
{ {
if (v2rayConfig.routing != null if (v2rayConfig.routing?.rules != null)
&& v2rayConfig.routing.rules != null)
{ {
v2rayConfig.routing.domainStrategy = config.domainStrategy; v2rayConfig.routing.domainStrategy = config.routingBasicItem.domainStrategy;
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.domainMatcher) ? null : config.domainMatcher; v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(config.routingBasicItem.domainMatcher) ? null : config.routingBasicItem.domainMatcher;
if (config.enableRoutingAdvanced) if (config.routingBasicItem.enableRoutingAdvanced)
{ {
var routing = ConfigHandler.GetDefaultRouting(ref config); var routing = ConfigHandler.GetDefaultRouting(ref config);
if (routing != null) if (routing != null)
@@ -228,6 +228,7 @@ namespace v2rayN.Handler
} }
return 0; return 0;
} }
private static int routingUserRule(RulesItem rules, ref V2rayConfig v2rayConfig) private static int routingUserRule(RulesItem rules, ref V2rayConfig v2rayConfig)
{ {
try try
@@ -240,25 +241,25 @@ namespace v2rayN.Handler
{ {
rules.port = null; rules.port = null;
} }
if (rules.domain != null && rules.domain.Count == 0) if (rules.domain?.Count == 0)
{ {
rules.domain = null; rules.domain = null;
} }
if (rules.ip != null && rules.ip.Count == 0) if (rules.ip?.Count == 0)
{ {
rules.ip = null; rules.ip = null;
} }
if (rules.protocol != null && rules.protocol.Count == 0) if (rules.protocol?.Count == 0)
{ {
rules.protocol = null; rules.protocol = null;
} }
if (rules.inboundTag != null && rules.inboundTag.Count == 0) if (rules.inboundTag?.Count == 0)
{ {
rules.inboundTag = null; rules.inboundTag = null;
} }
var hasDomainIp = false; var hasDomainIp = false;
if (rules.domain != null && rules.domain.Count > 0) if (rules.domain?.Count > 0)
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
it.ip = null; it.ip = null;
@@ -274,7 +275,7 @@ namespace v2rayN.Handler
v2rayConfig.routing.rules.Add(it); v2rayConfig.routing.rules.Add(it);
hasDomainIp = true; hasDomainIp = true;
} }
if (rules.ip != null && rules.ip.Count > 0) if (rules.ip?.Count > 0)
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
it.domain = null; it.domain = null;
@@ -285,8 +286,8 @@ namespace v2rayN.Handler
if (!hasDomainIp) if (!hasDomainIp)
{ {
if (!Utils.IsNullOrEmpty(rules.port) if (!Utils.IsNullOrEmpty(rules.port)
|| (rules.protocol != null && rules.protocol.Count > 0) || (rules.protocol?.Count > 0)
|| (rules.inboundTag != null && rules.inboundTag.Count > 0) || (rules.inboundTag?.Count > 0)
) )
{ {
var it = Utils.DeepCopy(rules); var it = Utils.DeepCopy(rules);
@@ -347,8 +348,8 @@ namespace v2rayN.Handler
} }
//Mux //Mux
outbound.mux.enabled = config.muxEnabled; outbound.mux.enabled = config.coreBasicItem.muxEnabled;
outbound.mux.concurrency = config.muxEnabled ? 8 : -1; outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
boundStreamSettings(node, "out", outbound.streamSettings); boundStreamSettings(node, "out", outbound.streamSettings);
@@ -372,7 +373,6 @@ namespace v2rayN.Handler
serversItem.password = node.id; serversItem.password = node.id;
serversItem.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none"; serversItem.method = LazyConfig.Instance.GetShadowsocksSecuritys(node).Contains(node.security) ? node.security : "none";
serversItem.ota = false; serversItem.ota = false;
serversItem.level = 1; serversItem.level = 1;
@@ -404,7 +404,7 @@ namespace v2rayN.Handler
if (!Utils.IsNullOrEmpty(node.security) if (!Utils.IsNullOrEmpty(node.security)
&& !Utils.IsNullOrEmpty(node.id)) && !Utils.IsNullOrEmpty(node.id))
{ {
SocksUsersItem socksUsersItem = new SocksUsersItem SocksUsersItem socksUsersItem = new()
{ {
user = node.security, user = node.security,
pass = node.id, pass = node.id,
@@ -451,27 +451,13 @@ namespace v2rayN.Handler
usersItem.encryption = node.security; usersItem.encryption = node.security;
//Mux //Mux
outbound.mux.enabled = config.muxEnabled; outbound.mux.enabled = config.coreBasicItem.muxEnabled;
outbound.mux.concurrency = config.muxEnabled ? 8 : -1; outbound.mux.concurrency = config.coreBasicItem.muxEnabled ? 8 : -1;
boundStreamSettings(node, "out", outbound.streamSettings); boundStreamSettings(node, "out", outbound.streamSettings);
//if xtls if (node.streamSecurity == Global.StreamSecurityReality
if (node.streamSecurity == Global.StreamSecurityX) || node.streamSecurity == Global.StreamSecurity)
{
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 (!Utils.IsNullOrEmpty(node.flow)) if (!Utils.IsNullOrEmpty(node.flow))
{ {
@@ -505,22 +491,6 @@ namespace v2rayN.Handler
serversItem.ota = false; serversItem.ota = false;
serversItem.level = 1; 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.enabled = false;
outbound.mux.concurrency = -1; outbound.mux.concurrency = -1;
@@ -547,15 +517,15 @@ namespace v2rayN.Handler
string host = node.requestHost.TrimEx(); string host = node.requestHost.TrimEx();
string sni = node.sni; string sni = node.sni;
string useragent = ""; string useragent = "";
if (!config.defUserAgent.IsNullOrEmpty()) if (!config.coreBasicItem.defUserAgent.IsNullOrEmpty())
{ {
try try
{ {
useragent = Global.userAgentTxt[config.defUserAgent]; useragent = Global.userAgentTxt[config.coreBasicItem.defUserAgent];
} }
catch (KeyNotFoundException) catch (KeyNotFoundException)
{ {
useragent = config.defUserAgent; useragent = config.coreBasicItem.defUserAgent;
} }
} }
@@ -564,11 +534,11 @@ namespace v2rayN.Handler
{ {
streamSettings.security = node.streamSecurity; streamSettings.security = node.streamSecurity;
TlsSettings tlsSettings = new TlsSettings TlsSettings tlsSettings = new()
{ {
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.defAllowInsecure.ToString().ToLower() : node.allowInsecure), allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(), alpn = node.GetAlpn(),
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.defFingerprint : node.fingerprint fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint
}; };
if (!string.IsNullOrWhiteSpace(sni)) if (!string.IsNullOrWhiteSpace(sni))
{ {
@@ -581,43 +551,38 @@ namespace v2rayN.Handler
streamSettings.tlsSettings = tlsSettings; streamSettings.tlsSettings = tlsSettings;
} }
//if xtls //if Reality
if (node.streamSecurity == Global.StreamSecurityX) if (node.streamSecurity == Global.StreamSecurityReality)
{ {
streamSettings.security = node.streamSecurity; streamSettings.security = node.streamSecurity;
TlsSettings xtlsSettings = new TlsSettings TlsSettings realitySettings = new()
{ {
allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.defAllowInsecure.ToString().ToLower() : node.allowInsecure), fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint,
alpn = node.GetAlpn(), serverName = sni,
fingerprint = node.fingerprint.IsNullOrEmpty() ? config.defFingerprint : node.fingerprint publicKey = node.publicKey,
shortId = node.shortId,
spiderX = node.spiderX,
}; };
if (!string.IsNullOrWhiteSpace(sni))
{ streamSettings.realitySettings = realitySettings;
xtlsSettings.serverName = sni;
}
else if (!string.IsNullOrWhiteSpace(host))
{
xtlsSettings.serverName = Utils.String2List(host)[0];
}
streamSettings.xtlsSettings = xtlsSettings;
} }
//streamSettings //streamSettings
switch (node.GetNetwork()) switch (node.GetNetwork())
{ {
case "kcp": case "kcp":
KcpSettings kcpSettings = new KcpSettings KcpSettings kcpSettings = new()
{ {
mtu = config.kcpItem.mtu, mtu = config.kcpItem.mtu,
tti = config.kcpItem.tti tti = config.kcpItem.tti
}; };
if (iobound.Equals("out")) if (iobound == "out")
{ {
kcpSettings.uplinkCapacity = config.kcpItem.uplinkCapacity; kcpSettings.uplinkCapacity = config.kcpItem.uplinkCapacity;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity; kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
} }
else if (iobound.Equals("in")) else if (iobound == "in")
{ {
kcpSettings.uplinkCapacity = config.kcpItem.downlinkCapacity; ; kcpSettings.uplinkCapacity = config.kcpItem.downlinkCapacity; ;
kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity; kcpSettings.downlinkCapacity = config.kcpItem.downlinkCapacity;
@@ -643,12 +608,8 @@ namespace v2rayN.Handler
break; break;
//ws //ws
case "ws": case "ws":
WsSettings wsSettings = new WsSettings WsSettings wsSettings = new();
{ wsSettings.headers = new Headers();
};
wsSettings.headers = new Headers
{
};
string path = node.path; string path = node.path;
if (!string.IsNullOrWhiteSpace(host)) if (!string.IsNullOrWhiteSpace(host))
{ {
@@ -664,17 +625,10 @@ namespace v2rayN.Handler
} }
streamSettings.wsSettings = wsSettings; streamSettings.wsSettings = wsSettings;
//TlsSettings tlsSettings = new TlsSettings();
//tlsSettings.allowInsecure = config.allowInsecure();
//if (!string.IsNullOrWhiteSpace(host))
//{
// tlsSettings.serverName = host;
//}
//streamSettings.tlsSettings = tlsSettings;
break; break;
//h2 //h2
case "h2": case "h2":
HttpSettings httpSettings = new HttpSettings(); HttpSettings httpSettings = new();
if (!string.IsNullOrWhiteSpace(host)) if (!string.IsNullOrWhiteSpace(host))
{ {
@@ -684,13 +638,10 @@ namespace v2rayN.Handler
streamSettings.httpSettings = httpSettings; streamSettings.httpSettings = httpSettings;
//TlsSettings tlsSettings2 = new TlsSettings();
//tlsSettings2.allowInsecure = config.allowInsecure();
//streamSettings.tlsSettings = tlsSettings2;
break; break;
//quic //quic
case "quic": case "quic":
QuicSettings quicsettings = new QuicSettings QuicSettings quicsettings = new()
{ {
security = host, security = host,
key = node.path, key = node.path,
@@ -712,8 +663,9 @@ namespace v2rayN.Handler
} }
} }
break; break;
case "grpc": case "grpc":
var grpcSettings = new GrpcSettings GrpcSettings grpcSettings = new()
{ {
serviceName = node.path, serviceName = node.path,
multiMode = (node.headerType == Global.GrpcmultiMode), multiMode = (node.headerType == Global.GrpcmultiMode),
@@ -722,14 +674,14 @@ namespace v2rayN.Handler
permit_without_stream = config.grpcItem.permit_without_stream, permit_without_stream = config.grpcItem.permit_without_stream,
initial_windows_size = config.grpcItem.initial_windows_size, initial_windows_size = config.grpcItem.initial_windows_size,
}; };
streamSettings.grpcSettings = grpcSettings; streamSettings.grpcSettings = grpcSettings;
break; break;
default: default:
//tcp //tcp
if (node.headerType.Equals(Global.TcpHeaderHttp)) if (node.headerType == Global.TcpHeaderHttp)
{ {
TcpSettings tcpSettings = new TcpSettings TcpSettings tcpSettings = new()
{ {
header = new Header header = new Header
{ {
@@ -737,7 +689,7 @@ namespace v2rayN.Handler
} }
}; };
if (iobound.Equals("out")) if (iobound == "out")
{ {
//request Host //request Host
string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName); string request = Utils.GetEmbedText(Global.v2raySampleHttprequestFileName);
@@ -756,7 +708,7 @@ namespace v2rayN.Handler
request = request.Replace("$requestPath$", $"\"{pathHttp}\""); request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
tcpSettings.header.request = Utils.FromJson<object>(request); tcpSettings.header.request = Utils.FromJson<object>(request);
} }
else if (iobound.Equals("in")) else if (iobound == "in")
{ {
//string response = Utils.GetEmbedText(Global.v2raySampleHttpresponseFileName); //string response = Utils.GetEmbedText(Global.v2raySampleHttpresponseFileName);
//tcpSettings.header.response = Utils.FromJson<object>(response); //tcpSettings.header.response = Utils.FromJson<object>(response);
@@ -792,13 +744,13 @@ namespace v2rayN.Handler
} }
var obj = Utils.ParseJson(config.remoteDNS); var obj = Utils.ParseJson(config.remoteDNS);
if (obj != null && obj.ContainsKey("servers")) if (obj?.ContainsKey("servers") == true)
{ {
v2rayConfig.dns = obj; v2rayConfig.dns = obj;
} }
else else
{ {
List<string> servers = new List<string>(); List<string> servers = new();
string[] arrDNS = config.remoteDNS.Split(','); string[] arrDNS = config.remoteDNS.Split(',');
foreach (string str in arrDNS) foreach (string str in arrDNS)
@@ -824,12 +776,12 @@ namespace v2rayN.Handler
private static int statistic(Config config, ref V2rayConfig v2rayConfig) private static int statistic(Config config, ref V2rayConfig v2rayConfig)
{ {
if (config.enableStatistics) if (config.guiItem.enableStatistics)
{ {
string tag = Global.InboundAPITagName; string tag = Global.InboundAPITagName;
API apiObj = new API(); API apiObj = new();
Policy policyObj = new Policy(); Policy policyObj = new();
SystemPolicy policySystemSetting = new SystemPolicy(); SystemPolicy policySystemSetting = new();
string[] services = { "StatsService" }; string[] services = { "StatsService" };
@@ -846,8 +798,8 @@ namespace v2rayN.Handler
if (!v2rayConfig.inbounds.Exists(item => item.tag == tag)) if (!v2rayConfig.inbounds.Exists(item => item.tag == tag))
{ {
Inbounds apiInbound = new Inbounds(); Inbounds apiInbound = new();
Inboundsettings apiInboundSettings = new Inboundsettings(); Inboundsettings apiInboundSettings = new();
apiInbound.tag = tag; apiInbound.tag = tag;
apiInbound.listen = Global.Loopback; apiInbound.listen = Global.Loopback;
apiInbound.port = Global.statePort; apiInbound.port = Global.statePort;
@@ -859,7 +811,7 @@ namespace v2rayN.Handler
if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag)) if (!v2rayConfig.routing.rules.Exists(item => item.outboundTag == tag))
{ {
RulesItem apiRoutingRule = new RulesItem RulesItem apiRoutingRule = new()
{ {
inboundTag = new List<string> { tag }, inboundTag = new List<string> { tag },
outboundTag = tag, outboundTag = tag,
@@ -878,11 +830,11 @@ namespace v2rayN.Handler
/// <param name="fileName"></param> /// <param name="fileName"></param>
/// <param name="msg"></param> /// <param name="msg"></param>
/// <returns></returns> /// <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 try
{ {
if (node == null) if (node == null || fileName is null)
{ {
msg = ResUI.CheckServerSettings; msg = ResUI.CheckServerSettings;
return -1; return -1;
@@ -924,9 +876,10 @@ namespace v2rayN.Handler
case ECoreType.Xray: case ECoreType.Xray:
case ECoreType.v2fly_v5: case ECoreType.v2fly_v5:
break; break;
case ECoreType.clash: case ECoreType.clash:
case ECoreType.clash_meta: case ECoreType.clash_meta:
//remove the original //remove the original
var indexPort = fileContent.FindIndex(t => t.Contains("port:")); var indexPort = fileContent.FindIndex(t => t.Contains("port:"));
if (indexPort >= 0) if (indexPort >= 0)
{ {
@@ -956,11 +909,12 @@ namespace v2rayN.Handler
return 0; return 0;
} }
public static int GenerateClientConfigContent(ProfileItem node, bool blExport, ref V2rayConfig v2rayConfig, out string msg) public static int GenerateClientConfigContent(ProfileItem node, bool blExport, ref V2rayConfig? v2rayConfig, out string msg)
{ {
try try
{ {
if (node == null) if (node == null
|| node.port <= 0)
{ {
msg = ResUI.CheckServerSettings; msg = ResUI.CheckServerSettings;
return -1; return -1;
@@ -1010,7 +964,7 @@ namespace v2rayN.Handler
return 0; return 0;
} }
#endregion #endregion Generate client configuration
#region Generate server-side configuration #region Generate server-side configuration
@@ -1033,7 +987,7 @@ namespace v2rayN.Handler
return -1; return -1;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
@@ -1085,7 +1039,6 @@ namespace v2rayN.Handler
{ {
inbound.protocol = Global.vmessProtocolLite; inbound.protocol = Global.vmessProtocolLite;
usersItem.alterId = node.alterId; usersItem.alterId = node.alterId;
} }
else if (node.configType == EConfigType.VLESS) else if (node.configType == EConfigType.VLESS)
{ {
@@ -1118,14 +1071,15 @@ namespace v2rayN.Handler
} }
return 0; return 0;
} }
#endregion
#endregion Generate server-side configuration
#region Import (export) client/server configuration #region Import (export) client/server configuration
public static ProfileItem ImportFromClientConfig(string fileName, out string msg) public static ProfileItem? ImportFromClientConfig(string fileName, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem(); ProfileItem profileItem = new();
try try
{ {
@@ -1136,7 +1090,7 @@ namespace v2rayN.Handler
return null; return null;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -1174,30 +1128,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}"; profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp //tcp or kcp
if (outbound.streamSettings != null if (outbound.streamSettings?.network != null
&& outbound.streamSettings.network != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.network)) && !Utils.IsNullOrEmpty(outbound.streamSettings.network))
{ {
profileItem.network = outbound.streamSettings.network; profileItem.network = outbound.streamSettings.network;
} }
//tcp http //tcp http
if (outbound.streamSettings != null if (outbound.streamSettings?.tcpSettings?.header != null
&& outbound.streamSettings.tcpSettings != null
&& outbound.streamSettings.tcpSettings.header != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.tcpSettings.header.type)) && !Utils.IsNullOrEmpty(outbound.streamSettings.tcpSettings.header.type))
{ {
if (outbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) if (outbound.streamSettings.tcpSettings.header.type == Global.TcpHeaderHttp)
{ {
profileItem.headerType = outbound.streamSettings.tcpSettings.header.type; profileItem.headerType = outbound.streamSettings.tcpSettings.header.type;
string request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request); string? request = Convert.ToString(outbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request)) if (!Utils.IsNullOrEmpty(request))
{ {
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request); V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null if (v2rayTcpRequest?.headers?.Host?.Count > 0)
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
{ {
profileItem.requestHost = v2rayTcpRequest.headers.Host[0]; profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
} }
@@ -1205,17 +1153,14 @@ namespace v2rayN.Handler
} }
} }
//kcp //kcp
if (outbound.streamSettings != null if (outbound?.streamSettings?.kcpSettings?.header != null
&& outbound.streamSettings.kcpSettings != null
&& outbound.streamSettings.kcpSettings.header != null
&& !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type)) && !Utils.IsNullOrEmpty(outbound.streamSettings.kcpSettings.header.type))
{ {
profileItem.headerType = outbound.streamSettings.kcpSettings.header.type; profileItem.headerType = outbound.streamSettings.kcpSettings.header.type;
} }
//ws //ws
if (outbound.streamSettings != null if (outbound?.streamSettings?.wsSettings != null)
&& outbound.streamSettings.wsSettings != null)
{ {
if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path)) if (!Utils.IsNullOrEmpty(outbound.streamSettings.wsSettings.path))
{ {
@@ -1229,24 +1174,20 @@ namespace v2rayN.Handler
} }
//h2 //h2
if (outbound.streamSettings != null if (outbound?.streamSettings?.httpSettings != null)
&& outbound.streamSettings.httpSettings != null)
{ {
if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path)) if (!Utils.IsNullOrEmpty(outbound.streamSettings.httpSettings.path))
{ {
profileItem.path = outbound.streamSettings.httpSettings.path; profileItem.path = outbound.streamSettings.httpSettings.path;
} }
if (outbound.streamSettings.httpSettings.host != null if (outbound.streamSettings.httpSettings.host?.Count > 0)
&& outbound.streamSettings.httpSettings.host.Count > 0)
{ {
profileItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host); profileItem.requestHost = Utils.List2String(outbound.streamSettings.httpSettings.host);
} }
} }
//tls //tls
if (outbound.streamSettings != null if (outbound?.streamSettings?.security == Global.StreamSecurity)
&& outbound.streamSettings.security != null
&& outbound.streamSettings.security == Global.StreamSecurity)
{ {
profileItem.streamSecurity = Global.StreamSecurity; profileItem.streamSecurity = Global.StreamSecurity;
} }
@@ -1261,21 +1202,21 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
public static ProfileItem ImportFromServerConfig(string fileName, out string msg) public static ProfileItem? ImportFromServerConfig(string fileName, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem(); ProfileItem profileItem = new();
try try
{ {
string result = Utils.LoadResource(fileName); string? result = Utils.LoadResource(fileName);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
msg = ResUI.FailedReadConfiguration; msg = ResUI.FailedReadConfiguration;
return null; return null;
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -1312,30 +1253,24 @@ namespace v2rayN.Handler
profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}"; profileItem.remarks = $"import@{DateTime.Now.ToShortDateString()}";
//tcp or kcp //tcp or kcp
if (inbound.streamSettings != null if (inbound.streamSettings?.network != null
&& inbound.streamSettings.network != null
&& !Utils.IsNullOrEmpty(inbound.streamSettings.network)) && !Utils.IsNullOrEmpty(inbound.streamSettings.network))
{ {
profileItem.network = inbound.streamSettings.network; profileItem.network = inbound.streamSettings.network;
} }
//tcp http //tcp http
if (inbound.streamSettings != null if (inbound.streamSettings?.tcpSettings?.header != null
&& inbound.streamSettings.tcpSettings != null
&& inbound.streamSettings.tcpSettings.header != null
&& !Utils.IsNullOrEmpty(inbound.streamSettings.tcpSettings.header.type)) && !Utils.IsNullOrEmpty(inbound.streamSettings.tcpSettings.header.type))
{ {
if (inbound.streamSettings.tcpSettings.header.type.Equals(Global.TcpHeaderHttp)) if (inbound.streamSettings.tcpSettings.header.type == Global.TcpHeaderHttp)
{ {
profileItem.headerType = inbound.streamSettings.tcpSettings.header.type; profileItem.headerType = inbound.streamSettings.tcpSettings.header.type;
string request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request); string? request = Convert.ToString(inbound.streamSettings.tcpSettings.header.request);
if (!Utils.IsNullOrEmpty(request)) if (!Utils.IsNullOrEmpty(request))
{ {
V2rayTcpRequest v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request); V2rayTcpRequest? v2rayTcpRequest = Utils.FromJson<V2rayTcpRequest>(request);
if (v2rayTcpRequest != null if (v2rayTcpRequest?.headers?.Host?.Count > 0)
&& v2rayTcpRequest.headers != null
&& v2rayTcpRequest.headers.Host != null
&& v2rayTcpRequest.headers.Host.Count > 0)
{ {
profileItem.requestHost = v2rayTcpRequest.headers.Host[0]; profileItem.requestHost = v2rayTcpRequest.headers.Host[0];
} }
@@ -1352,8 +1287,7 @@ namespace v2rayN.Handler
//} //}
//ws //ws
if (inbound.streamSettings != null if (inbound.streamSettings?.wsSettings != null)
&& inbound.streamSettings.wsSettings != null)
{ {
if (!Utils.IsNullOrEmpty(inbound.streamSettings.wsSettings.path)) if (!Utils.IsNullOrEmpty(inbound.streamSettings.wsSettings.path))
{ {
@@ -1367,24 +1301,20 @@ namespace v2rayN.Handler
} }
//h2 //h2
if (inbound.streamSettings != null if (inbound.streamSettings?.httpSettings != null)
&& inbound.streamSettings.httpSettings != null)
{ {
if (!Utils.IsNullOrEmpty(inbound.streamSettings.httpSettings.path)) if (!Utils.IsNullOrEmpty(inbound.streamSettings.httpSettings.path))
{ {
profileItem.path = inbound.streamSettings.httpSettings.path; profileItem.path = inbound.streamSettings.httpSettings.path;
} }
if (inbound.streamSettings.httpSettings.host != null if (inbound.streamSettings.httpSettings.host?.Count > 0)
&& inbound.streamSettings.httpSettings.host.Count > 0)
{ {
profileItem.requestHost = Utils.List2String(inbound.streamSettings.httpSettings.host); profileItem.requestHost = Utils.List2String(inbound.streamSettings.httpSettings.host);
} }
} }
//tls //tls
if (inbound.streamSettings != null if (inbound.streamSettings?.security == Global.StreamSecurity)
&& inbound.streamSettings.security != null
&& inbound.streamSettings.security == Global.StreamSecurity)
{ {
profileItem.streamSecurity = Global.StreamSecurity; profileItem.streamSecurity = Global.StreamSecurity;
} }
@@ -1400,7 +1330,7 @@ namespace v2rayN.Handler
public static int Export2ClientConfig(ProfileItem node, string fileName, out string msg) public static int Export2ClientConfig(ProfileItem node, string fileName, out string msg)
{ {
V2rayConfig v2rayConfig = null; V2rayConfig? v2rayConfig = null;
if (GenerateClientConfigContent(node, true, ref v2rayConfig, out msg) != 0) if (GenerateClientConfigContent(node, true, ref v2rayConfig, out msg) != 0)
{ {
return -1; return -1;
@@ -1413,11 +1343,10 @@ namespace v2rayN.Handler
return GenerateServerConfig(node, fileName, out msg); return GenerateServerConfig(node, fileName, out msg);
} }
#endregion #endregion Import (export) client/server configuration
#region Gen speedtest config #region Gen speedtest config
public static string GenerateClientSpeedtestConfigString(Config config, List<ServerTestItem> selecteds, out string msg) public static string GenerateClientSpeedtestConfigString(Config config, List<ServerTestItem> selecteds, out string msg)
{ {
try try
@@ -1439,14 +1368,14 @@ namespace v2rayN.Handler
return ""; return "";
} }
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfig = Utils.FromJson<V2rayConfig>(result);
if (v2rayConfig == null) if (v2rayConfig == null)
{ {
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
return ""; return "";
} }
List<IPEndPoint> lstIpEndPoints = new List<IPEndPoint>(); List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new List<TcpConnectionInformation>(); List<TcpConnectionInformation> lstTcpConns = new();
try try
{ {
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()); lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
@@ -1458,7 +1387,7 @@ namespace v2rayN.Handler
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);
} }
log(configCopy, ref v2rayConfig, false); log(configCopy, ref v2rayConfig, true);
//routing(config, ref v2rayConfig); //routing(config, ref v2rayConfig);
//dns(configCopy, ref v2rayConfig); //dns(configCopy, ref v2rayConfig);
@@ -1476,7 +1405,7 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (it.configType == EConfigType.VMess || it.configType == EConfigType.VLESS) if (it.configType is EConfigType.VMess or EConfigType.VLESS)
{ {
var item2 = LazyConfig.Instance.GetProfileItem(it.indexId); var item2 = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id)) if (item2 is null || Utils.IsNullOrEmpty(item2.id) || !Utils.IsGuidByParse(item2.id))
@@ -1489,11 +1418,11 @@ namespace v2rayN.Handler
var port = httpPort; var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++) for (int k = httpPort; k < Global.MaxPort; k++)
{ {
if (lstIpEndPoints != null && lstIpEndPoints.FindIndex(_it => _it.Port == k) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{ {
continue; continue;
} }
if (lstTcpConns != null && lstTcpConns.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0) if (lstTcpConns?.FindIndex(_it => _it.LocalEndPoint.Port == k) >= 0)
{ {
continue; continue;
} }
@@ -1504,7 +1433,7 @@ namespace v2rayN.Handler
} }
//Port In Used //Port In Used
if (lstIpEndPoints != null && lstIpEndPoints.FindIndex(_it => _it.Port == port) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == port) >= 0)
{ {
continue; continue;
} }
@@ -1512,7 +1441,7 @@ namespace v2rayN.Handler
it.allowTest = true; it.allowTest = true;
//inbound //inbound
Inbounds inbound = new Inbounds Inbounds inbound = new()
{ {
listen = Global.Loopback, listen = Global.Loopback,
port = port, port = port,
@@ -1522,7 +1451,7 @@ namespace v2rayN.Handler
v2rayConfig.inbounds.Add(inbound); v2rayConfig.inbounds.Add(inbound);
//outbound //outbound
V2rayConfig v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result); V2rayConfig? v2rayConfigCopy = Utils.FromJson<V2rayConfig>(result);
var item = LazyConfig.Instance.GetProfileItem(it.indexId); var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null) if (item is null)
{ {
@@ -1533,13 +1462,18 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (item.configType == EConfigType.VLESS
&& !Global.flows.Contains(item.flow))
{
continue;
}
outbound(item, ref v2rayConfigCopy); outbound(item, ref v2rayConfigCopy);
v2rayConfigCopy.outbounds[0].tag = Global.agentTag + inbound.port.ToString(); v2rayConfigCopy.outbounds[0].tag = Global.agentTag + inbound.port.ToString();
v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]); v2rayConfig.outbounds.Add(v2rayConfigCopy.outbounds[0]);
//rule //rule
RulesItem rule = new RulesItem RulesItem rule = new()
{ {
inboundTag = new List<string> { inbound.tag }, inboundTag = new List<string> { inbound.tag },
outboundTag = v2rayConfigCopy.outbounds[0].tag, outboundTag = v2rayConfigCopy.outbounds[0].tag,
@@ -1559,7 +1493,6 @@ namespace v2rayN.Handler
} }
} }
#endregion #endregion Gen speedtest config
} }
} }

View File

@@ -9,61 +9,61 @@ namespace v2rayN.Handler
/// <summary> /// <summary>
/// Core process processing class /// Core process processing class
/// </summary> /// </summary>
class CoreHandler internal class CoreHandler
{ {
private static string _coreCConfigRes = Global.coreConfigFileName; private static string _coreCConfigRes = Global.coreConfigFileName;
private CoreInfo _coreInfo; private CoreInfo? _coreInfo;
private int _processId = 0; private int _processId = 0;
private Process _process; private Process? _process;
Action<bool, string> _updateFunc; private Action<bool, string> _updateFunc;
public CoreHandler(Action<bool, string> update) public CoreHandler(Action<bool, string> update)
{ {
_updateFunc = update; _updateFunc = update;
Environment.SetEnvironmentVariable("v2ray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
} }
public void LoadCore(Config config) public void LoadCore(Config config)
{ {
if (Global.reloadCore) var node = ConfigHandler.GetDefaultServer(ref config);
if (node == null)
{ {
var node = ConfigHandler.GetDefaultServer(ref config); ShowMsg(false, ResUI.CheckServerSettings);
if (node == null) return;
{ }
ShowMsg(false, ResUI.CheckServerSettings);
return;
}
if (SetCore(config, node) != 0) if (SetCore(config, node) != 0)
{ {
ShowMsg(false, ResUI.CheckServerSettings); ShowMsg(false, ResUI.CheckServerSettings);
return; return;
} }
string fileName = Utils.GetConfigPath(_coreCConfigRes); string fileName = Utils.GetConfigPath(_coreCConfigRes);
if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0) if (CoreConfigHandler.GenerateClientConfig(node, fileName, out string msg, out string content) != 0)
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
} }
else else
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
ShowMsg(true, $"{node.GetSummary()}"); ShowMsg(true, $"{node.GetSummary()}");
CoreStop(); CoreStop();
CoreStart(node); CoreStart(node);
} }
//start a socks service //start a socks service
if (_process != null && !_process.HasExited && node.configType == EConfigType.Custom && node.preSocksPort > 0) if (_process != null && !_process.HasExited && node.configType == EConfigType.Custom && node.preSocksPort > 0)
{
var itemSocks = new ProfileItem()
{ {
var itemSocks = new ProfileItem() configType = EConfigType.Socks,
{ address = Global.Loopback,
configType = EConfigType.Socks, port = node.preSocksPort
address = Global.Loopback, };
port = node.preSocksPort if (CoreConfigHandler.GenerateClientConfig(itemSocks, null, out string msg2, out string configStr) == 0)
}; {
if (CoreConfigHandler.GenerateClientConfig(itemSocks, null, out string msg2, out string configStr) == 0) _processId = CoreStartViaString(configStr);
{
_processId = CoreStartViaString(configStr);
}
} }
} }
} }
@@ -105,7 +105,7 @@ namespace v2rayN.Handler
Process[] existing = Process.GetProcessesByName(vName); Process[] existing = Process.GetProcessesByName(vName);
foreach (Process p in existing) foreach (Process p in existing)
{ {
string path = p.MainModule.FileName; string? path = p.MainModule?.FileName;
if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe") if (path == $"{Utils.GetBinPath(vName, _coreInfo.coreType)}.exe")
{ {
KillProcess(p); KillProcess(p);
@@ -119,7 +119,6 @@ namespace v2rayN.Handler
CoreStopPid(_processId); CoreStopPid(_processId);
_processId = 0; _processId = 0;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -156,6 +155,7 @@ namespace v2rayN.Handler
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl); string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
Utils.SaveLog(msg);
ShowMsg(false, msg); ShowMsg(false, msg);
} }
return fileName; return fileName;
@@ -170,7 +170,8 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(_coreInfo); string fileName = CoreFindexe(_coreInfo);
if (fileName == "") return; if (fileName == "") return;
Process p = new Process var displayLog = node.configType != EConfigType.Custom || node.displayLog;
Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -178,18 +179,26 @@ namespace v2rayN.Handler
Arguments = _coreInfo.arguments, Arguments = _coreInfo.arguments,
WorkingDirectory = Utils.GetConfigPath(), WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = node.displayLog, RedirectStandardOutput = displayLog,
RedirectStandardError = node.displayLog, RedirectStandardError = displayLog,
CreateNoWindow = true, CreateNoWindow = true,
StandardOutputEncoding = node.displayLog ? Encoding.UTF8 : null, StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
StandardErrorEncoding = node.displayLog ? Encoding.UTF8 : null, StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
} }
}; };
if (node.displayLog) if (displayLog)
{ {
p.OutputDataReceived += (sender, e) => p.OutputDataReceived += (sender, e) =>
{ {
if (!String.IsNullOrEmpty(e.Data)) if (!string.IsNullOrEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
}
};
p.ErrorDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{ {
string msg = e.Data + Environment.NewLine; string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg); ShowMsg(false, msg);
@@ -197,21 +206,23 @@ namespace v2rayN.Handler
}; };
} }
p.Start(); p.Start();
if (node.displayLog) if (displayLog)
{ {
p.BeginOutputReadLine(); p.BeginOutputReadLine();
p.BeginErrorReadLine();
} }
_process = p; _process = p;
if (p.WaitForExit(1000)) if (p.WaitForExit(1000))
{ {
throw new Exception(node.displayLog ? p.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)"); throw new Exception(displayLog ? p.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)");
} }
Global.processJob.AddProcess(p.Handle); Global.processJob.AddProcess(p.Handle);
} }
catch (Exception ex) catch (Exception ex)
{ {
//Utils.SaveLog(Utils.ToJson(node));
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);
string msg = ex.Message; string msg = ex.Message;
ShowMsg(true, msg); ShowMsg(true, msg);
@@ -228,7 +239,7 @@ namespace v2rayN.Handler
string fileName = CoreFindexe(coreInfo); string fileName = CoreFindexe(coreInfo);
if (fileName == "") return -1; if (fileName == "") return -1;
Process p = new Process Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -252,8 +263,17 @@ namespace v2rayN.Handler
ShowMsg(false, msg); ShowMsg(false, msg);
} }
}; };
p.ErrorDataReceived += (sender, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
}
};
p.Start(); p.Start();
p.BeginOutputReadLine(); p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.StandardInput.Write(configStr); p.StandardInput.Write(configStr);
p.StandardInput.Close(); p.StandardInput.Close();
@@ -315,4 +335,4 @@ namespace v2rayN.Handler
return 0; return 0;
} }
} }
} }

View File

@@ -12,12 +12,11 @@ namespace v2rayN.Handler
/// <summary> /// <summary>
///Download ///Download
/// </summary> /// </summary>
class DownloadHandle internal class DownloadHandle
{ {
public event EventHandler<ResultEventArgs> UpdateCompleted; public event EventHandler<ResultEventArgs>? UpdateCompleted;
public event ErrorEventHandler Error;
public event ErrorEventHandler? Error;
public class ResultEventArgs : EventArgs public class ResultEventArgs : EventArgs
{ {
@@ -33,20 +32,13 @@ namespace v2rayN.Handler
public async Task<int> DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action<bool, string> update) public async Task<int> DownloadDataAsync(string url, WebProxy webProxy, int downloadTimeout, Action<bool, string> update)
{ {
var hasValue = false;
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = webProxy
});
var progress = new Progress<string>(); var progress = new Progress<string>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
{ {
hasValue = true;
if (update != null) if (update != null)
{ {
string msg = $"{value}"; string msg = $"{value}";
@@ -54,22 +46,17 @@ namespace v2rayN.Handler
} }
}; };
var cancellationToken = new CancellationTokenSource(); await DownloaderHelper.Instance.DownloadDataAsync4Speed(webProxy,
cancellationToken.CancelAfter(downloadTimeout * 1000);
await HttpClientHelper.GetInstance().DownloadDataAsync4Speed(client,
url, url,
progress, progress,
cancellationToken.Token); downloadTimeout);
} }
catch (Exception ex) catch (Exception ex)
{ {
if (!hasValue) update(false, ex.Message);
if (ex.InnerException != null)
{ {
update(false, ex.Message); update(false, ex.InnerException.Message);
if (ex.InnerException != null)
{
update(false, ex.InnerException.Message);
}
} }
} }
return 0; return 0;
@@ -79,30 +66,21 @@ namespace v2rayN.Handler
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading)); UpdateCompleted?.Invoke(this, new ResultEventArgs(false, ResUI.Downloading));
var client = new HttpClient(new SocketsHttpHandler()
{
Proxy = GetWebProxy(blProxy)
});
var progress = new Progress<double>(); var progress = new Progress<double>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
{ {
if (UpdateCompleted != null) UpdateCompleted?.Invoke(this, new ResultEventArgs(value > 100, $"...{value}%"));
{
string msg = $"...{value}%";
UpdateCompleted(this, new ResultEventArgs(value > 100 ? true : false, msg));
}
}; };
var cancellationToken = new CancellationTokenSource(); var webProxy = GetWebProxy(blProxy);
_ = HttpClientHelper.GetInstance().DownloadFileAsync(client, _ = DownloaderHelper.Instance.DownloadFileAsync(webProxy,
url, url,
Utils.GetTempPath(Utils.GetDownloadFileName(url)), Utils.GetTempPath(Utils.GetDownloadFileName(url)),
progress, progress,
cancellationToken.Token); downloadTimeout);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -116,18 +94,18 @@ namespace v2rayN.Handler
} }
} }
public async Task<string> UrlRedirectAsync(string url, bool blProxy) public async Task<string?> UrlRedirectAsync(string url, bool blProxy)
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webRequestHandler = new SocketsHttpHandler var webRequestHandler = new SocketsHttpHandler
{ {
AllowAutoRedirect = false, AllowAutoRedirect = false,
Proxy = GetWebProxy(blProxy) Proxy = GetWebProxy(blProxy)
}; };
HttpClient client = new HttpClient(webRequestHandler); HttpClient client = new(webRequestHandler);
HttpResponseMessage response = await client.GetAsync(url); HttpResponseMessage response = await client.GetAsync(url);
if (response.StatusCode.ToString() == "Redirect") if (response.StatusCode == HttpStatusCode.Redirect && response.Headers.Location is not null)
{ {
return response.Headers.Location.ToString(); return response.Headers.Location.ToString();
} }
@@ -138,27 +116,90 @@ namespace v2rayN.Handler
} }
} }
/// <summary> public async Task<string?> TryDownloadString(string url, bool blProxy, string userAgent)
/// DownloadString
/// </summary>
/// <param name="url"></param>
public async Task<string> DownloadStringAsync(string url, bool blProxy, string userAgent)
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().enableSecurityProtocolTls13); 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)
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
var client = new HttpClient(new SocketsHttpHandler() var client = new HttpClient(new SocketsHttpHandler()
{ {
Proxy = GetWebProxy(blProxy) Proxy = webProxy,
UseProxy = webProxy != null
}); });
if (Utils.IsNullOrEmpty(userAgent)) if (Utils.IsNullOrEmpty(userAgent))
{ {
userAgent = $"{Utils.GetVersion(false)}"; userAgent = Utils.GetVersion(false);
} }
client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent); client.DefaultRequestHeaders.UserAgent.TryParseAdd(userAgent);
Uri uri = new Uri(url); Uri uri = new(url);
//Authorization Header //Authorization Header
if (!Utils.IsNullOrEmpty(uri.UserInfo)) if (!Utils.IsNullOrEmpty(uri.UserInfo))
{ {
@@ -168,7 +209,7 @@ namespace v2rayN.Handler
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
cts.CancelAfter(1000 * 30); cts.CancelAfter(1000 * 30);
var result = await HttpClientHelper.GetInstance().GetAsync(client, url, cts.Token); var result = await HttpClientHelper.Instance.GetAsync(client, url, cts.Token);
return result; return result;
} }
catch (Exception ex) catch (Exception ex)
@@ -183,7 +224,38 @@ namespace v2rayN.Handler
return null; return null;
} }
public int RunAvailabilityCheck(WebProxy webProxy) /// <summary>
/// DownloadString
/// </summary>
/// <param name="url"></param>
public async Task<string?> DownloadStringViaDownloader(string url, bool blProxy, string userAgent)
{
try
{
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy);
if (Utils.IsNullOrEmpty(userAgent))
{
userAgent = Utils.GetVersion(false);
}
var result = await DownloaderHelper.Instance.DownloadStringAsync(webProxy, url, userAgent, 30);
return result;
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null)
{
Error?.Invoke(this, new ErrorEventArgs(ex.InnerException));
}
}
return null;
}
public int RunAvailabilityCheck(IWebProxy? webProxy)
{ {
try try
{ {
@@ -196,7 +268,7 @@ namespace v2rayN.Handler
try try
{ {
var config = LazyConfig.Instance.GetConfig(); var config = LazyConfig.Instance.GetConfig();
string status = GetRealPingTime(config.constItem.speedPingTestUrl, webProxy, 10, out int responseTime); string status = GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
bool noError = Utils.IsNullOrEmpty(status); bool noError = Utils.IsNullOrEmpty(status);
return noError ? responseTime : -1; return noError ? responseTime : -1;
} }
@@ -213,7 +285,7 @@ namespace v2rayN.Handler
} }
} }
public string GetRealPingTime(string url, WebProxy webProxy, int downloadTimeout, out int responseTime) public string GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout, out int responseTime)
{ {
string msg = string.Empty; string msg = string.Empty;
responseTime = -1; responseTime = -1;
@@ -223,19 +295,14 @@ namespace v2rayN.Handler
myHttpWebRequest.Timeout = downloadTimeout * 1000; myHttpWebRequest.Timeout = downloadTimeout * 1000;
myHttpWebRequest.Proxy = webProxy; myHttpWebRequest.Proxy = webProxy;
Stopwatch timer = new Stopwatch(); Stopwatch timer = Stopwatch.StartNew();
timer.Start();
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); using HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
if (myHttpWebResponse.StatusCode != HttpStatusCode.OK if (myHttpWebResponse.StatusCode is not HttpStatusCode.OK and not HttpStatusCode.NoContent)
&& myHttpWebResponse.StatusCode != HttpStatusCode.NoContent)
{ {
msg = myHttpWebResponse.StatusDescription; msg = myHttpWebResponse.StatusDescription;
} }
timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = timer.Elapsed.Milliseconds;
myHttpWebResponse.Close();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -245,7 +312,7 @@ namespace v2rayN.Handler
return msg; return msg;
} }
private WebProxy GetWebProxy(bool blProxy) private WebProxy? GetWebProxy(bool blProxy)
{ {
if (!blProxy) if (!blProxy)
{ {
@@ -262,25 +329,17 @@ namespace v2rayN.Handler
private bool SocketCheck(string ip, int port) private bool SocketCheck(string ip, int port)
{ {
Socket sock = null;
try try
{ {
IPAddress ipa = IPAddress.Parse(ip); IPEndPoint point = new(IPAddress.Parse(ip), port);
IPEndPoint point = new IPEndPoint(ipa, port); using Socket? sock = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(point); sock.Connect(point);
return true; return true;
} }
catch { } catch (Exception)
finally
{ {
if (sock != null) return false;
{
sock.Close();
sock.Dispose();
}
} }
return false;
} }
} }
} }

View File

@@ -0,0 +1,180 @@
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 public sealed class LazyConfig
{ {
private static readonly Lazy<LazyConfig> _instance = new Lazy<LazyConfig>(() => new()); private static readonly Lazy<LazyConfig> _instance = new(() => new());
private Config _config; private Config _config;
private List<CoreInfo> coreInfos; private List<CoreInfo> coreInfos;
@@ -17,14 +17,16 @@ namespace v2rayN.Handler
SqliteHelper.Instance.CreateTable<ProfileItem>(); SqliteHelper.Instance.CreateTable<ProfileItem>();
SqliteHelper.Instance.CreateTable<ServerStatItem>(); SqliteHelper.Instance.CreateTable<ServerStatItem>();
SqliteHelper.Instance.CreateTable<RoutingItem>(); SqliteHelper.Instance.CreateTable<RoutingItem>();
SqliteHelper.Instance.CreateTable<ProfileExItem>();
} }
#region Config #region Config
public void SetConfig(ref Config config) public void SetConfig(Config config)
{ {
_config = config; _config = config;
} }
public Config GetConfig() public Config GetConfig()
{ {
return _config; return _config;
@@ -64,6 +66,7 @@ namespace v2rayN.Handler
{ {
return SqliteHelper.Instance.Table<SubItem>().ToList(); return SqliteHelper.Instance.Table<SubItem>().ToList();
} }
public SubItem GetSubItem(string subid) public SubItem GetSubItem(string subid)
{ {
return SqliteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid); return SqliteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
@@ -74,7 +77,6 @@ namespace v2rayN.Handler
if (Utils.IsNullOrEmpty(subid)) if (Utils.IsNullOrEmpty(subid))
{ {
return SqliteHelper.Instance.Table<ProfileItem>().ToList(); return SqliteHelper.Instance.Table<ProfileItem>().ToList();
} }
else else
{ {
@@ -82,12 +84,24 @@ namespace v2rayN.Handler
} }
} }
public List<string> ProfileItemIndexs(string subid)
{
if (Utils.IsNullOrEmpty(subid))
{
return SqliteHelper.Instance.Table<ProfileItem>().Select(t => t.indexId).ToList();
}
else
{
return SqliteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).Select(t => t.indexId).ToList();
}
}
public List<ProfileItemModel> ProfileItems(string subid, string filter) public List<ProfileItemModel> ProfileItems(string subid, string filter)
{ {
var sql = @$"select a.* var sql = @$"select a.*
,b.remarks subRemarks ,b.remarks subRemarks
from ProfileItem a from ProfileItem a
left join SubItem b on a.subid = b.id left join SubItem b on a.subid = b.id
where 1=1 "; where 1=1 ";
if (!Utils.IsNullOrEmpty(subid)) if (!Utils.IsNullOrEmpty(subid))
{ {
@@ -95,18 +109,17 @@ namespace v2rayN.Handler
} }
if (!Utils.IsNullOrEmpty(filter)) if (!Utils.IsNullOrEmpty(filter))
{ {
if (filter.Contains("'")) if (filter.Contains('\''))
{ {
filter = filter.Replace("'", ""); filter = filter.Replace("'", "");
} }
sql += $" and a.remarks like '%{filter}%'"; sql += 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(); return SqliteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
} }
public ProfileItem GetProfileItem(string indexId) public ProfileItem? GetProfileItem(string indexId)
{ {
if (Utils.IsNullOrEmpty(indexId)) if (Utils.IsNullOrEmpty(indexId))
{ {
@@ -115,38 +128,17 @@ namespace v2rayN.Handler
return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId); return SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
} }
public Task SetTestResult(string indexId, string delayVal, string speedVal)
{
string sql = string.Empty;
if (!Utils.IsNullOrEmpty(delayVal) && !Utils.IsNullOrEmpty(speedVal))
{
int.TryParse(delayVal, out int delay);
decimal.TryParse(speedVal, out decimal speed);
sql = $"update ProfileItem set delay={delay},speed={speed} where indexId = '{indexId}'";
}
else if (!Utils.IsNullOrEmpty(delayVal))
{
int.TryParse(delayVal, out int delay);
sql = $"update ProfileItem set delay={delay} where indexId = '{indexId}'";
}
else if (!Utils.IsNullOrEmpty(speedVal))
{
decimal.TryParse(speedVal, out decimal speed);
sql = $"update ProfileItem set speed={speed} where indexId = '{indexId}'";
}
return SqliteHelper.Instance.ExecuteAsync(sql);
}
public List<RoutingItem> RoutingItems() public List<RoutingItem> RoutingItems()
{ {
return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).ToList(); return SqliteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
} }
public RoutingItem GetRoutingItem(string id) public RoutingItem GetRoutingItem(string id)
{ {
return SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id); return SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
} }
#endregion #endregion Config
#region Core Type #region Core Type
@@ -166,7 +158,7 @@ namespace v2rayN.Handler
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType) public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
{ {
if (profileItem != null && profileItem.coreType != null) if (profileItem?.coreType != null)
{ {
return (ECoreType)profileItem.coreType; return (ECoreType)profileItem.coreType;
} }
@@ -183,16 +175,16 @@ namespace v2rayN.Handler
return item.coreType; return item.coreType;
} }
public CoreInfo GetCoreInfo(ECoreType coreType) public CoreInfo? GetCoreInfo(ECoreType coreType)
{ {
if (coreInfos == null) if (coreInfos == null)
{ {
InitCoreInfo(); InitCoreInfo();
} }
return coreInfos.Where(t => t.coreType == coreType).FirstOrDefault(); return coreInfos!.FirstOrDefault(t => t.coreType == coreType);
} }
public List<CoreInfo> GetCoreInfos() public List<CoreInfo>? GetCoreInfos()
{ {
if (coreInfos == null) if (coreInfos == null)
{ {
@@ -203,15 +195,16 @@ namespace v2rayN.Handler
private void InitCoreInfo() private void InitCoreInfo()
{ {
coreInfos = new List<CoreInfo>(); coreInfos = new(16);
coreInfos.Add(new CoreInfo coreInfos.Add(new CoreInfo
{ {
coreType = ECoreType.v2rayN, coreType = ECoreType.v2rayN,
coreUrl = Global.NUrl, coreUrl = Global.NUrl,
coreReleaseApiUrl = Global.NUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.NUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN.zip", coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip", coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip"
}); });
coreInfos.Add(new CoreInfo coreInfos.Add(new CoreInfo
@@ -220,9 +213,10 @@ namespace v2rayN.Handler
coreExes = new List<string> { "wv2ray", "v2ray" }, coreExes = new List<string> { "wv2ray", "v2ray" },
arguments = "", arguments = "",
coreUrl = Global.v2flyCoreUrl, coreUrl = Global.v2flyCoreUrl,
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
versionArg = "-version", versionArg = "-version",
redirectInfo = true, redirectInfo = true,
@@ -234,9 +228,10 @@ namespace v2rayN.Handler
coreExes = new List<string> { "SagerNet", "v2ray" }, coreExes = new List<string> { "SagerNet", "v2ray" },
arguments = "run", arguments = "run",
coreUrl = Global.SagerNetCoreUrl, coreUrl = Global.SagerNetCoreUrl,
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl32 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.SagerNetCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
versionArg = "version", versionArg = "version",
redirectInfo = true, redirectInfo = true,
@@ -248,9 +243,10 @@ namespace v2rayN.Handler
coreExes = new List<string> { "v2ray" }, coreExes = new List<string> { "v2ray" },
arguments = "run", arguments = "run",
coreUrl = Global.v2flyCoreUrl, coreUrl = Global.v2flyCoreUrl,
coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.v2flyCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl32 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip", coreDownloadUrl64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.v2flyCoreUrl + "/download/{0}/v2ray-windows-{1}.zip",
match = "V2Ray", match = "V2Ray",
versionArg = "version", versionArg = "version",
redirectInfo = true, redirectInfo = true,
@@ -262,9 +258,10 @@ namespace v2rayN.Handler
coreExes = new List<string> { "xray", "wxray" }, coreExes = new List<string> { "xray", "wxray" },
arguments = "", arguments = "",
coreUrl = Global.xrayCoreUrl, coreUrl = Global.xrayCoreUrl,
coreReleaseApiUrl = Global.xrayCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.xrayCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", coreDownloadUrl32 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip", coreDownloadUrl64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
coreDownloadUrlArm64 = Global.xrayCoreUrl + "/download/{0}/Xray-windows-{1}.zip",
match = "Xray", match = "Xray",
versionArg = "-version", versionArg = "-version",
redirectInfo = true, redirectInfo = true,
@@ -276,9 +273,10 @@ namespace v2rayN.Handler
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" }, coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
arguments = "-f config.json", arguments = "-f config.json",
coreUrl = Global.clashCoreUrl, coreUrl = Global.clashCoreUrl,
coreReleaseApiUrl = Global.clashCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.clashCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip", coreDownloadUrl32 = Global.clashCoreUrl + "/download/{0}/clash-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip", coreDownloadUrl64 = Global.clashCoreUrl + "/download/{0}/clash-windows-amd64-{0}.zip",
coreDownloadUrlArm64 = Global.clashCoreUrl + "/download/{0}/clash-windows-arm64-{0}.zip",
match = "v", match = "v",
versionArg = "-v", versionArg = "-v",
redirectInfo = true, redirectInfo = true,
@@ -290,9 +288,10 @@ namespace v2rayN.Handler
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" }, coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
arguments = "-f config.json", arguments = "-f config.json",
coreUrl = Global.clashMetaCoreUrl, coreUrl = Global.clashMetaCoreUrl,
coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.clashMetaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip", coreDownloadUrl32 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-386-{0}.zip",
coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip", coreDownloadUrl64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-amd64-compatible-{0}.zip",
coreDownloadUrlArm64 = Global.clashMetaCoreUrl + "/download/{0}/Clash.Meta-windows-arm64-{0}.zip",
match = "v", match = "v",
versionArg = "-v", versionArg = "-v",
redirectInfo = true, redirectInfo = true,
@@ -304,9 +303,10 @@ namespace v2rayN.Handler
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
arguments = "", arguments = "",
coreUrl = Global.hysteriaCoreUrl, coreUrl = Global.hysteriaCoreUrl,
coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(@"https://github.com", @"https://api.github.com/repos"), coreReleaseApiUrl = Global.hysteriaCoreUrl.Replace(Global.githubUrl, Global.githubApiUrl),
coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe", coreDownloadUrl32 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-386.exe",
coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe", coreDownloadUrl64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-amd64.exe",
coreDownloadUrlArm64 = Global.hysteriaCoreUrl + "/download/{0}/hysteria-windows-arm64.exe",
redirectInfo = true, redirectInfo = true,
}); });
@@ -335,9 +335,15 @@ namespace v2rayN.Handler
arguments = "run", arguments = "run",
coreUrl = Global.singboxCoreUrl, coreUrl = Global.singboxCoreUrl,
redirectInfo = true, 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",
}); });
} }
#endregion #endregion Core Type
} }
} }

View File

@@ -1,9 +1,6 @@
using NHotkey; using Microsoft.Win32;
using NHotkey.Wpf;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx; using v2rayN.Resx;
@@ -12,15 +9,7 @@ namespace v2rayN.Handler
{ {
public sealed class MainFormHandler public sealed class MainFormHandler
{ {
private static readonly Lazy<MainFormHandler> instance = new Lazy<MainFormHandler>(() => new MainFormHandler()); private static readonly Lazy<MainFormHandler> instance = new(() => new());
//Action<bool, string> _updateUI;
//private DownloadHandle downloadHandle2;
//private Config _config;
//private V2rayHandler _v2rayHandler;
//private List<int> _selecteds;
//private Thread _workThread;
//Action<int, string> _updateFunc;
public static MainFormHandler Instance => instance.Value; public static MainFormHandler Instance => instance.Value;
public Icon GetNotifyIcon(Config config) public Icon GetNotifyIcon(Config config)
@@ -42,19 +31,14 @@ namespace v2rayN.Handler
{ {
return new Icon(fileName); return new Icon(fileName);
} }
switch (index) return index switch
{ {
case 0: 0 => Properties.Resources.NotifyIcon1,
return Properties.Resources.NotifyIcon1; 1 => Properties.Resources.NotifyIcon2,
case 1: 2 => Properties.Resources.NotifyIcon3,
return Properties.Resources.NotifyIcon2; 3 => Properties.Resources.NotifyIcon2,
case 2: _ => Properties.Resources.NotifyIcon1, // default
return Properties.Resources.NotifyIcon3; };
case 3:
return Properties.Resources.NotifyIcon2;
}
return Properties.Resources.NotifyIcon1;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -71,10 +55,12 @@ namespace v2rayN.Handler
case 0: case 0:
index = 1; index = 1;
break; break;
case 1: case 1:
case 3: case 3:
index = 2; index = 2;
break; break;
case 2: case 2:
index = 3; index = 3;
break; break;
@@ -82,11 +68,11 @@ namespace v2rayN.Handler
return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute)); return BitmapFrame.Create(new Uri($"pack://application:,,,/Resources/NotifyIcon{index}.ico", UriKind.RelativeOrAbsolute));
} }
private Icon GetNotifyIcon4Routing(Config config) private Icon? GetNotifyIcon4Routing(Config config)
{ {
try try
{ {
if (!config.enableRoutingAdvanced) if (!config.routingBasicItem.enableRoutingAdvanced)
{ {
return null; return null;
} }
@@ -107,12 +93,12 @@ namespace v2rayN.Handler
int width = 128; int width = 128;
int height = 128; int height = 128;
Bitmap bitmap = new Bitmap(width, height); Bitmap bitmap = new(width, height);
Graphics graphics = Graphics.FromImage(bitmap); Graphics graphics = Graphics.FromImage(bitmap);
SolidBrush drawBrush = new SolidBrush(color); SolidBrush drawBrush = new(color);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height)); //graphics.FillRectangle(drawBrush, new Rectangle(0, 0, width, height));
graphics.DrawImage(new Bitmap(item.customIcon), 0, 0, width, height); graphics.DrawImage(new Bitmap(item.customIcon), 0, 0, width, height);
graphics.FillEllipse(drawBrush, width / 2, width / 2, width / 2, width / 2); graphics.FillEllipse(drawBrush, width / 2, width / 2, width / 2, width / 2);
@@ -143,13 +129,13 @@ namespace v2rayN.Handler
return; return;
} }
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
Filter = "Config|*.json", Filter = "Config|*.json",
FilterIndex = 2, FilterIndex = 2,
RestoreDirectory = true RestoreDirectory = true
}; };
if (fileDialog.ShowDialog() != DialogResult.OK) if (fileDialog.ShowDialog() != true)
{ {
return; return;
} }
@@ -176,20 +162,19 @@ namespace v2rayN.Handler
{ {
return; return;
} }
if (item.configType != EConfigType.VMess if (item.configType is not EConfigType.VMess and not EConfigType.VLESS)
&& item.configType != EConfigType.VLESS)
{ {
UI.Show(ResUI.NonVmessService); UI.Show(ResUI.NonVmessService);
return; return;
} }
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
Filter = "Config|*.json", Filter = "Config|*.json",
FilterIndex = 2, FilterIndex = 2,
RestoreDirectory = true RestoreDirectory = true
}; };
if (fileDialog.ShowDialog() != DialogResult.OK) if (fileDialog.ShowDialog() != true)
{ {
return; return;
} }
@@ -212,21 +197,21 @@ namespace v2rayN.Handler
public void BackupGuiNConfig(Config config, bool auto = false) public void BackupGuiNConfig(Config config, bool auto = false)
{ {
string fileName = $"guiNConfig_{DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss_fff")}.json"; string fileName = $"guiNConfig_{DateTime.Now:yyyy_MM_dd_HH_mm_ss_fff}.json";
if (auto) if (auto)
{ {
fileName = Utils.GetBackupPath(fileName); fileName = Utils.GetBackupPath(fileName);
} }
else else
{ {
SaveFileDialog fileDialog = new SaveFileDialog SaveFileDialog fileDialog = new()
{ {
FileName = fileName, FileName = fileName,
Filter = "guiNConfig|*.json", Filter = "guiNConfig|*.json",
FilterIndex = 2, FilterIndex = 2,
RestoreDirectory = true RestoreDirectory = true
}; };
if (fileDialog.ShowDialog() != DialogResult.OK) if (fileDialog.ShowDialog() != true)
{ {
return; return;
} }
@@ -241,7 +226,6 @@ namespace v2rayN.Handler
{ {
if (ret == 0) if (ret == 0)
{ {
UI.Show(ResUI.OperationSuccess); UI.Show(ResUI.OperationSuccess);
} }
else else
@@ -254,22 +238,22 @@ namespace v2rayN.Handler
public bool RestoreGuiNConfig(ref Config config) public bool RestoreGuiNConfig(ref Config config)
{ {
var fileContent = string.Empty; var fileContent = string.Empty;
using (OpenFileDialog fileDialog = new OpenFileDialog()) OpenFileDialog fileDialog = new();
{
fileDialog.InitialDirectory = Utils.GetBackupPath("");
fileDialog.Filter = "guiNConfig|*.json|All|*.*";
fileDialog.FilterIndex = 2;
fileDialog.RestoreDirectory = true;
if (fileDialog.ShowDialog() == DialogResult.OK) fileDialog.InitialDirectory = Utils.GetBackupPath("");
{ fileDialog.Filter = "guiNConfig|*.json|All|*.*";
fileContent = Utils.LoadResource(fileDialog.FileName); fileDialog.FilterIndex = 2;
} fileDialog.RestoreDirectory = true;
else
{ if (fileDialog.ShowDialog() == true)
return false; {
} fileContent = Utils.LoadResource(fileDialog.FileName);
} }
else
{
return false;
}
if (Utils.IsNullOrEmpty(fileContent)) if (Utils.IsNullOrEmpty(fileContent))
{ {
UI.ShowWarning(ResUI.OperationFailed); UI.ShowWarning(ResUI.OperationFailed);
@@ -286,47 +270,62 @@ namespace v2rayN.Handler
BackupGuiNConfig(config, true); BackupGuiNConfig(config, true);
config = resConfig; config = resConfig;
LazyConfig.Instance.SetConfig(ref config); LazyConfig.Instance.SetConfig(config);
return true; return true;
} }
public void UpdateTask(Config config, Action<bool, string> update) 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)
{
Thread.Sleep(60000);
Utils.SaveLog("UpdateTaskRunSubscription");
var updateHandle = new UpdateHandle();
while (true)
{
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();
foreach (var item in lstSubs)
{
updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) =>
{
update(success, msg);
if (success)
Utils.SaveLog("subscription" + msg);
});
item.updateTime = updateTime;
ConfigHandler.AddSubItem(ref config, item);
Thread.Sleep(5000);
}
Thread.Sleep(60000);
}
}
private void UpdateTaskRunGeo(Config config, Action<bool, string> update)
{ {
var autoUpdateSubTime = DateTime.Now;
var autoUpdateGeoTime = DateTime.Now; var autoUpdateGeoTime = DateTime.Now;
Thread.Sleep(60000); Thread.Sleep(1000 * 120);
Utils.SaveLog("UpdateTaskRun"); Utils.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateHandle(); var updateHandle = new UpdateHandle();
while (true) while (true)
{ {
var dtNow = DateTime.Now; var dtNow = DateTime.Now;
if (config.guiItem.autoUpdateInterval > 0)
if (config.autoUpdateSubInterval > 0)
{ {
if ((dtNow - autoUpdateSubTime).Hours % config.autoUpdateSubInterval == 0) if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
{
updateHandle.UpdateSubscriptionProcess(config, "", true, (bool success, string msg) =>
{
update(success, msg);
if (success)
Utils.SaveLog("subscription" + msg);
});
autoUpdateSubTime = dtNow;
}
Thread.Sleep(60000);
}
if (config.autoUpdateInterval > 0)
{
if ((dtNow - autoUpdateGeoTime).Hours % config.autoUpdateInterval == 0)
{ {
updateHandle.UpdateGeoFile("geosite", config, (bool success, string msg) => updateHandle.UpdateGeoFile("geosite", config, (bool success, string msg) =>
{ {
@@ -349,49 +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) HotkeyHandler.Instance.UpdateViewEvent += update;
{ HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
return; HotkeyHandler.Instance.Load();
}
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);
}
}
} }
} }
} }

View File

@@ -18,16 +18,16 @@ namespace v2rayN.Handler
{ {
_snackbarMessageQueue?.Enqueue(content); _snackbarMessageQueue?.Enqueue(content);
} }
public void SendMessage(string msg) public void SendMessage(string msg)
{ {
MessageBus.Current.SendMessage(msg, "MsgView"); MessageBus.Current.SendMessage(msg, "MsgView");
} }
public void SendMessage(string msg, bool time) public void SendMessage(string msg, bool time)
{ {
msg = $"{DateTime.Now} {msg}"; msg = $"{DateTime.Now} {msg}";
MessageBus.Current.SendMessage(msg, "MsgView"); MessageBus.Current.SendMessage(msg, "MsgView");
} }
} }
} }

View File

@@ -0,0 +1,145 @@
using System.Collections.Concurrent;
using System.Reactive.Linq;
using v2rayN.Base;
using v2rayN.Mode;
namespace v2rayN.Handler
{
internal 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

@@ -3,23 +3,23 @@ using System.Runtime.InteropServices;
namespace v2rayN.Handler namespace v2rayN.Handler
{ {
class ProxySetting internal class ProxySetting
{ {
public static bool UnsetProxy() public static bool UnsetProxy()
{ {
return SetProxy(null, null, 1); return SetProxy(null, null, 1);
} }
public static bool SetProxy(string strProxy, string exceptions, int type) public static bool SetProxy(string? strProxy, string? exceptions, int type)
{ {
InternetPerConnOptionList list = new InternetPerConnOptionList(); InternetPerConnOptionList list = new();
int optionCount = 1; int optionCount = 1;
if (type == 1) if (type == 1)
{ {
optionCount = 1; optionCount = 1;
} }
else if (type == 2 || type == 4) else if (type is 2 or 4)
{ {
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3; optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
} }
@@ -62,7 +62,6 @@ namespace v2rayN.Handler
list.dwOptionCount = options.Length; list.dwOptionCount = options.Length;
list.dwOptionError = 0; list.dwOptionError = 0;
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption)); int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
// make a pointer out of all that ... // make a pointer out of all that ...
IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length);
@@ -71,12 +70,12 @@ namespace v2rayN.Handler
{ {
if (Environment.Is64BitOperatingSystem) if (Environment.Is64BitOperatingSystem)
{ {
IntPtr opt = new IntPtr(optionsPtr.ToInt64() + (i * optSize)); IntPtr opt = new(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
else else
{ {
IntPtr opt = new IntPtr(optionsPtr.ToInt32() + (i * optSize)); IntPtr opt = new(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
} }
@@ -84,7 +83,7 @@ namespace v2rayN.Handler
list.options = optionsPtr; list.options = optionsPtr;
// and then make a pointer out of the whole list // and then make a pointer out of the whole list
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem((int)list.dwSize); IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize);
Marshal.StructureToPtr(list, ipcoListPtr, false); Marshal.StructureToPtr(list, ipcoListPtr, false);
// and finally, call the API method! // and finally, call the API method!
@@ -106,8 +105,8 @@ namespace v2rayN.Handler
return (returnvalue < 0); return (returnvalue < 0);
} }
#region WinInet structures #region WinInet structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetPerConnOptionList public struct InternetPerConnOptionList
{ {
@@ -115,6 +114,7 @@ namespace v2rayN.Handler
public IntPtr szConnection; // connection name to set/query options public IntPtr szConnection; // connection name to set/query options
public int dwOptionCount; // number of options to set/query public int dwOptionCount; // number of options to set/query
public int dwOptionError; // on error, which option failed public int dwOptionError; // on error, which option failed
//[MarshalAs(UnmanagedType.)] //[MarshalAs(UnmanagedType.)]
public IntPtr options; public IntPtr options;
}; };
@@ -122,9 +122,10 @@ namespace v2rayN.Handler
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption public struct InternetConnectionOption
{ {
static readonly int Size; private static readonly int Size;
public PerConnOption m_Option; public PerConnOption m_Option;
public InternetConnectionOptionValue m_Value; public InternetConnectionOptionValue m_Value;
static InternetConnectionOption() static InternetConnectionOption()
{ {
Size = Marshal.SizeOf(typeof(InternetConnectionOption)); Size = Marshal.SizeOf(typeof(InternetConnectionOption));
@@ -137,15 +138,19 @@ namespace v2rayN.Handler
// Fields // Fields
[FieldOffset(0)] [FieldOffset(0)]
public System.Runtime.InteropServices.ComTypes.FILETIME m_FileTime; public System.Runtime.InteropServices.ComTypes.FILETIME m_FileTime;
[FieldOffset(0)] [FieldOffset(0)]
public int m_Int; public int m_Int;
[FieldOffset(0)] [FieldOffset(0)]
public IntPtr m_StringPtr; public IntPtr m_StringPtr;
} }
} }
#endregion
#endregion WinInet structures
#region WinInet enums #region WinInet enums
// //
// options manifests for Internet{Query|Set}Option // options manifests for Internet{Query|Set}Option
// //
@@ -159,11 +164,10 @@ namespace v2rayN.Handler
// //
public enum PerConnOption public enum PerConnOption
{ {
INTERNET_PER_CONN_FLAGS = 1, // Sets or retrieves the connection type. The Value member will contain one or more of the values from PerConnFlags INTERNET_PER_CONN_FLAGS = 1, // Sets or retrieves the connection type. The Value member will contain one or more of the values from PerConnFlags
INTERNET_PER_CONN_PROXY_SERVER = 2, // Sets or retrieves a string containing the proxy servers. INTERNET_PER_CONN_PROXY_SERVER = 2, // Sets or retrieves a string containing the proxy servers.
INTERNET_PER_CONN_PROXY_BYPASS = 3, // Sets or retrieves a string containing the URLs that do not use the proxy server. INTERNET_PER_CONN_PROXY_BYPASS = 3, // Sets or retrieves a string containing the URLs that do not use the proxy server.
INTERNET_PER_CONN_AUTOCONFIG_URL = 4//, // Sets or retrieves a string containing the URL to the automatic configuration script. INTERNET_PER_CONN_AUTOCONFIG_URL = 4//, // Sets or retrieves a string containing the URL to the automatic configuration script.
} }
// //
@@ -177,7 +181,8 @@ namespace v2rayN.Handler
PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
} }
#endregion
#endregion WinInet enums
internal static class NativeMethods internal static class NativeMethods
{ {
@@ -189,26 +194,23 @@ namespace v2rayN.Handler
//判断是否使用代理 //判断是否使用代理
public static bool UsedProxy() public static bool UsedProxy()
{ {
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
if (rk.GetValue("ProxyEnable").ToString() == "1") if (rk?.GetValue("ProxyEnable")?.ToString() == "1")
{ {
rk.Close();
return true; return true;
} }
else else
{ {
rk.Close();
return false; return false;
} }
} }
//获得代理的IP和端口
public static string GetProxyProxyServer()
{
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
string ProxyServer = rk.GetValue("ProxyServer").ToString();
rk.Close();
return ProxyServer;
//获得代理的IP和端口
public static string? GetProxyProxyServer()
{
using RegistryKey? rk = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
string ProxyServer = rk.GetValue("ProxyServer").ToString();
return ProxyServer;
} }
} }
} }

View File

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

View File

@@ -7,9 +7,8 @@ using v2rayN.Resx;
namespace v2rayN.Handler namespace v2rayN.Handler
{ {
class ShareHandler internal class ShareHandler
{ {
#region GetShareUrl #region GetShareUrl
/// <summary> /// <summary>
@@ -17,32 +16,22 @@ namespace v2rayN.Handler
/// </summary> /// </summary>
/// <param name="item"></param> /// <param name="item"></param>
/// <returns></returns> /// <returns></returns>
public static string GetShareUrl(ProfileItem item) public static string? GetShareUrl(ProfileItem item)
{ {
try try
{ {
string url = string.Empty; string? url = string.Empty;
switch (item.configType) url = item.configType switch
{ {
case EConfigType.VMess: EConfigType.VMess => ShareVmess(item),
url = ShareVmess(item); EConfigType.Shadowsocks => ShareShadowsocks(item),
break; EConfigType.Socks => ShareSocks(item),
case EConfigType.Shadowsocks: EConfigType.Trojan => ShareTrojan(item),
url = ShareShadowsocks(item); EConfigType.VLESS => ShareVLESS(item),
break; _ => null,
case EConfigType.Socks: };
url = ShareSocks(item);
break;
case EConfigType.Trojan:
url = ShareTrojan(item);
break;
case EConfigType.VLESS:
url = ShareVLESS(item);
break;
default:
break;
}
return url; return url;
} }
catch (Exception ex) catch (Exception ex)
@@ -56,10 +45,10 @@ namespace v2rayN.Handler
{ {
string url = string.Empty; string url = string.Empty;
VmessQRCode vmessQRCode = new VmessQRCode VmessQRCode vmessQRCode = new()
{ {
v = item.configVersion.ToString(), v = item.configVersion.ToString(),
ps = item.remarks.TrimEx(), //备注也许很长 ; ps = item.remarks.TrimEx(),
add = item.address, add = item.address,
port = item.port.ToString(), port = item.port.ToString(),
id = item.id, id = item.id,
@@ -172,12 +161,13 @@ namespace v2rayN.Handler
url = $"{Global.vlessProtocol}{url}{query}{remark}"; url = $"{Global.vlessProtocol}{url}{query}{remark}";
return url; return url;
} }
private static string GetIpv6(string address) private static string GetIpv6(string address)
{ {
return Utils.IsIpv6(address) ? $"[{address}]" : address; return Utils.IsIpv6(address) ? $"[{address}]" : address;
} }
private static int GetStdTransport(ProfileItem item, string securityDef, ref Dictionary<string, string> dicQuery) private static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
{ {
if (!Utils.IsNullOrEmpty(item.flow)) if (!Utils.IsNullOrEmpty(item.flow))
{ {
@@ -207,6 +197,18 @@ namespace v2rayN.Handler
{ {
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint)); 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"); dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : "tcp");
@@ -219,6 +221,7 @@ namespace v2rayN.Handler
dicQuery.Add("host", Utils.UrlEncode(item.requestHost)); dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
} }
break; break;
case "kcp": case "kcp":
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none"); dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : "none");
if (!Utils.IsNullOrEmpty(item.path)) if (!Utils.IsNullOrEmpty(item.path))
@@ -256,11 +259,12 @@ namespace v2rayN.Handler
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost)); dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
dicQuery.Add("key", Utils.UrlEncode(item.path)); dicQuery.Add("key", Utils.UrlEncode(item.path));
break; break;
case "grpc": case "grpc":
if (!Utils.IsNullOrEmpty(item.path)) if (!Utils.IsNullOrEmpty(item.path))
{ {
dicQuery.Add("serviceName", Utils.UrlEncode(item.path)); dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
if (item.headerType == Global.GrpcgunMode || item.headerType == Global.GrpcmultiMode) if (item.headerType is Global.GrpcgunMode or Global.GrpcmultiMode)
{ {
dicQuery.Add("mode", Utils.UrlEncode(item.headerType)); dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
} }
@@ -270,25 +274,24 @@ namespace v2rayN.Handler
return 0; return 0;
} }
#endregion #endregion GetShareUrl
#region ImportShareUrl
#region ImportShareUrl
/// <summary> /// <summary>
/// 从剪贴板导入URL /// 从剪贴板导入URL
/// </summary> /// </summary>
/// <param name="fileName"></param>
/// <param name="msg"></param> /// <param name="msg"></param>
/// <returns></returns> /// <returns></returns>
public static ProfileItem ImportFromClipboardConfig(string clipboardData, out string msg) public static ProfileItem? ImportFromClipboardConfig(string clipboardData, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
ProfileItem profileItem = new ProfileItem();
ProfileItem profileItem = new();
try try
{ {
//载入配置文件 //载入配置文件
string result = clipboardData.TrimEx();// Utils.GetClipboardData(); string result = clipboardData.TrimEx();// Utils.GetClipboardData();
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
@@ -307,7 +310,6 @@ namespace v2rayN.Handler
{ {
profileItem = ResolveVmess(result, out msg); profileItem = ResolveVmess(result, out msg);
} }
} }
else if (result.StartsWith(Global.ssProtocol)) else if (result.StartsWith(Global.ssProtocol))
{ {
@@ -350,7 +352,6 @@ namespace v2rayN.Handler
else if (result.StartsWith(Global.vlessProtocol)) else if (result.StartsWith(Global.vlessProtocol))
{ {
profileItem = ResolveStdVLESS(result); profileItem = ResolveStdVLESS(result);
} }
else else
{ {
@@ -368,7 +369,7 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveVmess(string result, out string msg) private static ProfileItem? ResolveVmess(string result, out string msg)
{ {
msg = string.Empty; msg = string.Empty;
var profileItem = new ProfileItem var profileItem = new ProfileItem
@@ -376,11 +377,11 @@ namespace v2rayN.Handler
configType = EConfigType.VMess configType = EConfigType.VMess
}; };
result = result.Substring(Global.vmessProtocol.Length); result = result[Global.vmessProtocol.Length..];
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
//转成Json //转成Json
VmessQRCode vmessQRCode = Utils.FromJson<VmessQRCode>(result); VmessQRCode? vmessQRCode = Utils.FromJson<VmessQRCode>(result);
if (vmessQRCode == null) if (vmessQRCode == null)
{ {
msg = ResUI.FailedConversionConfiguration; msg = ResUI.FailedConversionConfiguration;
@@ -418,17 +419,17 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveVmess4Kitsunebi(string result) private static ProfileItem? ResolveVmess4Kitsunebi(string result)
{ {
ProfileItem profileItem = new ProfileItem ProfileItem profileItem = new()
{ {
configType = EConfigType.VMess configType = EConfigType.VMess
}; };
result = result.Substring(Global.vmessProtocol.Length); result = result[Global.vmessProtocol.Length..];
int indexSplit = result.IndexOf("?"); int indexSplit = result.IndexOf("?");
if (indexSplit > 0) if (indexSplit > 0)
{ {
result = result.Substring(0, indexSplit); result = result[..indexSplit];
} }
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
@@ -439,7 +440,7 @@ namespace v2rayN.Handler
} }
string[] arr21 = arr1[0].Split(':'); string[] arr21 = arr1[0].Split(':');
string[] arr22 = arr1[1].Split(':'); string[] arr22 = arr1[1].Split(':');
if (arr21.Length != 2 || arr21.Length != 2) if (arr21.Length != 2 || arr22.Length != 2)
{ {
return null; return null;
} }
@@ -456,15 +457,15 @@ namespace v2rayN.Handler
return profileItem; return profileItem;
} }
private static ProfileItem ResolveStdVmess(string result) private static ProfileItem? ResolveStdVmess(string result)
{ {
ProfileItem i = new ProfileItem ProfileItem i = new()
{ {
configType = EConfigType.VMess, configType = EConfigType.VMess,
security = "auto" security = "auto"
}; };
Uri u = new Uri(result); Uri u = new(result);
i.address = u.IdnHost; i.address = u.IdnHost;
i.port = u.Port; i.port = u.Port;
@@ -485,6 +486,7 @@ namespace v2rayN.Handler
case "tls": case "tls":
// TODO tls config // TODO tls config
break; break;
default: default:
if (!string.IsNullOrWhiteSpace(i.streamSecurity)) if (!string.IsNullOrWhiteSpace(i.streamSecurity))
return null; return null;
@@ -500,6 +502,7 @@ namespace v2rayN.Handler
// TODO http option // TODO http option
break; break;
case "kcp": case "kcp":
i.headerType = q["type"] ?? "none"; i.headerType = q["type"] ?? "none";
// TODO kcp seed // TODO kcp seed
@@ -537,7 +540,7 @@ namespace v2rayN.Handler
return i; return i;
} }
private static ProfileItem ResolveSip002(string result) private static ProfileItem? ResolveSip002(string result)
{ {
Uri parsedUrl; Uri parsedUrl;
try try
@@ -548,7 +551,7 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
ProfileItem server = new ProfileItem ProfileItem server = new()
{ {
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost, address = parsedUrl.IdnHost,
@@ -556,7 +559,7 @@ namespace v2rayN.Handler
}; };
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped); string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
//2022-blake3 //2022-blake3
if (rawUserInfo.Contains(":")) if (rawUserInfo.Contains(':'))
{ {
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2) if (userInfoParts.Length != 2)
@@ -600,16 +603,16 @@ namespace v2rayN.Handler
return server; return server;
} }
private static readonly Regex UrlFinder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase); private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex DetailsParser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase); private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static ProfileItem ResolveSSLegacy(string result) private static ProfileItem? ResolveSSLegacy(string result)
{ {
var match = UrlFinder.Match(result); var match = UrlFinder.Match(result);
if (!match.Success) if (!match.Success)
return null; return null;
ProfileItem server = new ProfileItem(); ProfileItem server = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/'); var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value; var tag = match.Groups["tag"].Value;
if (!Utils.IsNullOrEmpty(tag)) if (!Utils.IsNullOrEmpty(tag))
@@ -634,17 +637,16 @@ namespace v2rayN.Handler
return server; return server;
} }
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 readonly Regex StdVmessUserInfo = new Regex( private static ProfileItem? ResolveSocks(string result)
@"^(?<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 ProfileItem ResolveSocks(string result)
{ {
ProfileItem profileItem = new ProfileItem ProfileItem profileItem = new()
{ {
configType = EConfigType.Socks configType = EConfigType.Socks
}; };
result = result.Substring(Global.socksProtocol.Length); result = result[Global.socksProtocol.Length..];
//remark //remark
int indexRemark = result.IndexOf("#"); int indexRemark = result.IndexOf("#");
if (indexRemark > 0) if (indexRemark > 0)
@@ -654,7 +656,7 @@ namespace v2rayN.Handler
profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1)); profileItem.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
} }
catch { } catch { }
result = result.Substring(0, indexRemark); result = result[..indexRemark];
} }
//part decode //part decode
int indexS = result.IndexOf("@"); int indexS = result.IndexOf("@");
@@ -678,15 +680,15 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
profileItem.address = arr1[1].Substring(0, indexPort); profileItem.address = arr1[1][..indexPort];
profileItem.port = Utils.ToInt(arr1[1].Substring(indexPort + 1, arr1[1].Length - (indexPort + 1))); profileItem.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
profileItem.security = arr21[0]; profileItem.security = arr21[0];
profileItem.id = arr21[1]; profileItem.id = arr21[1];
return profileItem; return profileItem;
} }
private static ProfileItem ResolveSocksNew(string result) private static ProfileItem? ResolveSocksNew(string result)
{ {
Uri parsedUrl; Uri parsedUrl;
try try
@@ -697,7 +699,7 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
ProfileItem server = new ProfileItem ProfileItem server = new()
{ {
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped), remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost, address = parsedUrl.IdnHost,
@@ -719,12 +721,12 @@ namespace v2rayN.Handler
private static ProfileItem ResolveTrojan(string result) private static ProfileItem ResolveTrojan(string result)
{ {
ProfileItem item = new ProfileItem ProfileItem item = new()
{ {
configType = EConfigType.Trojan configType = EConfigType.Trojan
}; };
Uri url = new Uri(result); Uri url = new(result);
item.address = url.IdnHost; item.address = url.IdnHost;
item.port = url.Port; item.port = url.Port;
@@ -736,15 +738,16 @@ namespace v2rayN.Handler
return item; return item;
} }
private static ProfileItem ResolveStdVLESS(string result) private static ProfileItem ResolveStdVLESS(string result)
{ {
ProfileItem item = new ProfileItem ProfileItem item = new()
{ {
configType = EConfigType.VLESS, configType = EConfigType.VLESS,
security = "none" security = "none"
}; };
Uri url = new Uri(result); Uri url = new(result);
item.address = url.IdnHost; item.address = url.IdnHost;
item.port = url.Port; item.port = url.Port;
@@ -766,6 +769,10 @@ namespace v2rayN.Handler
item.sni = query["sni"] ?? ""; item.sni = query["sni"] ?? "";
item.alpn = Utils.UrlDecode(query["alpn"] ?? ""); item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
item.fingerprint = Utils.UrlDecode(query["fp"] ?? ""); item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
item.network = query["type"] ?? "tcp"; item.network = query["type"] ?? "tcp";
switch (item.network) switch (item.network)
{ {
@@ -774,6 +781,7 @@ namespace v2rayN.Handler
item.requestHost = Utils.UrlDecode(query["host"] ?? ""); item.requestHost = Utils.UrlDecode(query["host"] ?? "");
break; break;
case "kcp": case "kcp":
item.headerType = query["headerType"] ?? "none"; item.headerType = query["headerType"] ?? "none";
item.path = Utils.UrlDecode(query["seed"] ?? ""); item.path = Utils.UrlDecode(query["seed"] ?? "");
@@ -796,16 +804,18 @@ namespace v2rayN.Handler
item.requestHost = query["quicSecurity"] ?? "none"; item.requestHost = query["quicSecurity"] ?? "none";
item.path = Utils.UrlDecode(query["key"] ?? ""); item.path = Utils.UrlDecode(query["key"] ?? "");
break; break;
case "grpc": case "grpc":
item.path = Utils.UrlDecode(query["serviceName"] ?? ""); item.path = Utils.UrlDecode(query["serviceName"] ?? "");
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcgunMode); item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcgunMode);
break; break;
default: default:
break; break;
} }
return 0; return 0;
} }
#endregion #endregion ImportShareUrl
} }
} }

View File

@@ -7,13 +7,13 @@ using v2rayN.Resx;
namespace v2rayN.Handler namespace v2rayN.Handler
{ {
class SpeedtestHandler internal class SpeedtestHandler
{ {
private Config _config; private Config _config;
private CoreHandler _coreHandler; private CoreHandler _coreHandler;
private List<ServerTestItem> _selecteds; private List<ServerTestItem> _selecteds;
private ESpeedActionType _actionType; private ESpeedActionType _actionType;
Action<string, string, string> _updateFunc; private Action<string, string, string> _updateFunc;
public SpeedtestHandler(Config config) public SpeedtestHandler(Config config)
{ {
@@ -34,6 +34,10 @@ namespace v2rayN.Handler
{ {
continue; continue;
} }
if (it.port <= 0)
{
continue;
}
_selecteds.Add(new ServerTestItem() _selecteds.Add(new ServerTestItem()
{ {
indexId = it.indexId, indexId = it.indexId,
@@ -51,12 +55,18 @@ namespace v2rayN.Handler
case ESpeedActionType.Tcping: case ESpeedActionType.Tcping:
case ESpeedActionType.Realping: case ESpeedActionType.Realping:
UpdateFunc(it.indexId, ResUI.Speedtesting, ""); UpdateFunc(it.indexId, ResUI.Speedtesting, "");
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
break; break;
case ESpeedActionType.Speedtest: case ESpeedActionType.Speedtest:
UpdateFunc(it.indexId, "", ResUI.Speedtesting); UpdateFunc(it.indexId, "", ResUI.SpeedtestingWait);
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break; break;
case ESpeedActionType.Mixedtest: case ESpeedActionType.Mixedtest:
UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.Speedtesting); UpdateFunc(it.indexId, ResUI.Speedtesting, ResUI.SpeedtestingWait);
ProfileExHandler.Instance.SetTestDelay(it.indexId, "0");
ProfileExHandler.Instance.SetTestSpeed(it.indexId, "0");
break; break;
} }
} }
@@ -66,15 +76,19 @@ namespace v2rayN.Handler
case ESpeedActionType.Ping: case ESpeedActionType.Ping:
Task.Run(RunPing); Task.Run(RunPing);
break; break;
case ESpeedActionType.Tcping: case ESpeedActionType.Tcping:
Task.Run(RunTcping); Task.Run(RunTcping);
break; break;
case ESpeedActionType.Realping: case ESpeedActionType.Realping:
Task.Run(RunRealPing); Task.Run(RunRealPing);
break; break;
case ESpeedActionType.Speedtest: case ESpeedActionType.Speedtest:
Task.Run(RunSpeedTestAsync); Task.Run(RunSpeedTestAsync);
break; break;
case ESpeedActionType.Mixedtest: case ESpeedActionType.Mixedtest:
Task.Run(RunMixedtestAsync); Task.Run(RunMixedtestAsync);
break; break;
@@ -105,7 +119,6 @@ namespace v2rayN.Handler
} }
} }
private void RunPing() private void RunPing()
{ {
RunPingSub((ServerTestItem it) => RunPingSub((ServerTestItem it) =>
@@ -113,7 +126,7 @@ namespace v2rayN.Handler
long time = Ping(it.address); long time = Ping(it.address);
var output = FormatOut(time, Global.DelayUnit); var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
@@ -125,7 +138,7 @@ namespace v2rayN.Handler
int time = GetTcpingTime(it.address, it.port); int time = GetTcpingTime(it.address, it.port);
var output = FormatOut(time, Global.DelayUnit); var output = FormatOut(time, Global.DelayUnit);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
}); });
} }
@@ -146,7 +159,7 @@ namespace v2rayN.Handler
DownloadHandle downloadHandle = new DownloadHandle(); DownloadHandle downloadHandle = new DownloadHandle();
//Thread.Sleep(5000); //Thread.Sleep(5000);
List<Task> tasks = new List<Task>(); List<Task> tasks = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (!it.allowTest) if (!it.allowTest)
@@ -161,12 +174,10 @@ namespace v2rayN.Handler
{ {
try try
{ {
LazyConfig.Instance.SetTestResult(it.indexId, "-1", ""); WebProxy webProxy = new(Global.Loopback, it.port);
WebProxy webProxy = new WebProxy(Global.Loopback, it.port);
string output = GetRealPingTime(downloadHandle, webProxy); string output = GetRealPingTime(downloadHandle, webProxy);
LazyConfig.Instance.SetTestResult(it.indexId, output, ""); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output); UpdateFunc(it.indexId, output);
int.TryParse(output, out int delay); int.TryParse(output, out int delay);
it.delay = delay; it.delay = delay;
@@ -187,6 +198,7 @@ namespace v2rayN.Handler
finally finally
{ {
if (pid > 0) _coreHandler.CoreStopPid(pid); if (pid > 0) _coreHandler.CoreStopPid(pid);
ProfileExHandler.Instance.SaveTo();
} }
return Task.CompletedTask; return Task.CompletedTask;
@@ -195,10 +207,10 @@ namespace v2rayN.Handler
private async Task RunSpeedTestAsync() private async Task RunSpeedTestAsync()
{ {
int pid = -1; int pid = -1;
if (_actionType == ESpeedActionType.Mixedtest) //if (_actionType == ESpeedActionType.Mixedtest)
{ //{
_selecteds = _selecteds.OrderBy(t => t.delay).ToList(); // _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
} //}
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds); pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
if (pid < 0) if (pid < 0)
@@ -207,10 +219,68 @@ namespace v2rayN.Handler
return; return;
} }
string url = _config.constItem.speedTestUrl; string url = _config.speedTestItem.speedTestUrl;
DownloadHandle downloadHandle = new DownloadHandle(); var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new();
foreach (var it in _selecteds)
{
if (!it.allowTest)
{
continue;
}
if (it.configType == EConfigType.Custom)
{
continue;
}
//if (it.delay < 0)
//{
// UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
// continue;
//}
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(Global.Loopback, it.port);
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) =>
{
decimal.TryParse(msg, out decimal dec);
if (dec > 0)
{
ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
}
UpdateFunc(it.indexId, "", msg);
});
}
if (pid > 0)
{
_coreHandler.CoreStopPid(pid);
}
UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
}
private async Task RunSpeedTestMulti()
{
int pid = -1;
pid = _coreHandler.LoadCoreConfigString(_config, _selecteds);
if (pid < 0)
{
UpdateFunc("", ResUI.FailedToRunCore);
return;
}
string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new();
var timeout = 8;
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (!it.allowTest) if (!it.allowTest)
@@ -226,42 +296,47 @@ namespace v2rayN.Handler
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
continue; continue;
} }
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", "-1"); ProfileExHandler.Instance.SetTestSpeed(it.indexId, "-1");
UpdateFunc(it.indexId, "", ResUI.Speedtesting);
var item = LazyConfig.Instance.GetProfileItem(it.indexId); var item = LazyConfig.Instance.GetProfileItem(it.indexId);
if (item is null) continue; if (item is null) continue;
WebProxy webProxy = new WebProxy(Global.Loopback, it.port); WebProxy webProxy = new(Global.Loopback, it.port);
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) =>
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (bool success, string msg) =>
{ {
decimal.TryParse(msg, out decimal dec); decimal.TryParse(msg, out decimal dec);
if (dec > 0) if (dec > 0)
{ {
_ = LazyConfig.Instance.SetTestResult(it.indexId, "", msg); ProfileExHandler.Instance.SetTestSpeed(it.indexId, msg);
} }
UpdateFunc(it.indexId, "", msg); UpdateFunc(it.indexId, "", msg);
}); });
Thread.Sleep(2000);
} }
Thread.Sleep((timeout + 2) * 1000);
if (pid > 0) if (pid > 0)
{ {
_coreHandler.CoreStopPid(pid); _coreHandler.CoreStopPid(pid);
} }
UpdateFunc("", ResUI.SpeedtestingCompleted); UpdateFunc("", ResUI.SpeedtestingCompleted);
ProfileExHandler.Instance.SaveTo();
} }
private async Task RunMixedtestAsync() private async Task RunMixedtestAsync()
{ {
await RunRealPing(); await RunRealPing();
Thread.Sleep(1000); Thread.Sleep(1000);
await RunSpeedTestAsync(); await RunSpeedTestMulti();
} }
public string GetRealPingTime(DownloadHandle downloadHandle, WebProxy webProxy) public string GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy)
{ {
string status = downloadHandle.GetRealPingTime(_config.constItem.speedPingTestUrl, webProxy, 10, out int responseTime); string status = downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10, out int responseTime);
//string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status; //string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit); return FormatOut(Utils.IsNullOrEmpty(status) ? responseTime : -1, Global.DelayUnit);
} }
@@ -278,11 +353,11 @@ namespace v2rayN.Handler
ipAddress = ipHostInfo.AddressList[0]; ipAddress = ipHostInfo.AddressList[0];
} }
Stopwatch timer = new Stopwatch(); Stopwatch timer = new();
timer.Start(); timer.Start();
IPEndPoint endPoint = new IPEndPoint(ipAddress, port); IPEndPoint endPoint = new(ipAddress, port);
Socket clientSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null); IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))) if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
@@ -291,7 +366,6 @@ namespace v2rayN.Handler
timer.Stop(); timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = timer.Elapsed.Milliseconds;
clientSocket.Close();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -300,7 +374,6 @@ namespace v2rayN.Handler
return responseTime; return responseTime;
} }
/// <summary> /// <summary>
/// Ping /// Ping
/// </summary> /// </summary>
@@ -313,7 +386,7 @@ namespace v2rayN.Handler
{ {
int timeout = 30; int timeout = 30;
int echoNum = 2; int echoNum = 2;
Ping pingSender = new Ping(); using Ping pingSender = new();
for (int i = 0; i < echoNum; i++) for (int i = 0; i < echoNum; i++)
{ {
PingReply reply = pingSender.Send(host, timeout); PingReply reply = pingSender.Send(host, timeout);
@@ -352,4 +425,4 @@ namespace v2rayN.Handler
_updateFunc(indexId, delay, speed); _updateFunc(indexId, delay, speed);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Grpc.Core; using Grpc.Core;
using Grpc.Net.Client;
using ProtosLib.Statistics; using ProtosLib.Statistics;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
@@ -7,17 +8,17 @@ using v2rayN.Mode;
namespace v2rayN.Handler namespace v2rayN.Handler
{ {
class StatisticsHandler internal class StatisticsHandler
{ {
private Mode.Config config_; private Mode.Config config_;
private Channel channel_; private GrpcChannel _channel;
private StatsService.StatsServiceClient client_; private StatsService.StatsServiceClient _client;
private bool exitFlag_; private bool _exitFlag;
private ServerStatItem _serverStatItem; private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat; private List<ServerStatItem> _lstServerStat;
public List<ServerStatItem> ServerStat => _lstServerStat; public List<ServerStatItem> ServerStat => _lstServerStat;
Action<ServerSpeedItem> updateFunc_; private Action<ServerSpeedItem> _updateFunc;
public bool Enable public bool Enable
{ {
@@ -27,9 +28,9 @@ namespace v2rayN.Handler
public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update) public StatisticsHandler(Mode.Config config, Action<ServerSpeedItem> update)
{ {
config_ = config; config_ = config;
Enable = config.enableStatistics; Enable = config.guiItem.enableStatistics;
updateFunc_ = update; _updateFunc = update;
exitFlag_ = false; _exitFlag = false;
Init(); Init();
GrpcInit(); GrpcInit();
@@ -39,13 +40,12 @@ namespace v2rayN.Handler
private void GrpcInit() private void GrpcInit()
{ {
if (channel_ == null) if (_channel == null)
{ {
Global.statePort = GetFreePort(); Global.statePort = GetFreePort();
channel_ = new Channel($"{Global.Loopback}:{Global.statePort}", ChannelCredentials.Insecure); _channel = GrpcChannel.ForAddress($"{Global.httpProtocol}{Global.Loopback}:{Global.statePort}");
channel_.ConnectAsync(); _client = new StatsService.StatsServiceClient(_channel);
client_ = new StatsService.StatsServiceClient(channel_);
} }
} }
@@ -53,8 +53,8 @@ namespace v2rayN.Handler
{ {
try try
{ {
exitFlag_ = true; _exitFlag = true;
channel_.ShutdownAsync(); //channel_.ShutdownAsync();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -62,18 +62,18 @@ namespace v2rayN.Handler
} }
} }
public void Run() public async void Run()
{ {
while (!exitFlag_) while (!_exitFlag)
{ {
try try
{ {
if (Enable && channel_.State == ChannelState.Ready) if (Enable && _channel.State == ConnectivityState.Ready)
{ {
QueryStatsResponse res = null; QueryStatsResponse? res = null;
try try
{ {
res = client_.QueryStats(new QueryStatsRequest() { Pattern = "", Reset = true }); res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -99,13 +99,13 @@ namespace v2rayN.Handler
server.todayDown = _serverStatItem.todayDown; server.todayDown = _serverStatItem.todayDown;
server.totalUp = _serverStatItem.totalUp; server.totalUp = _serverStatItem.totalUp;
server.totalDown = _serverStatItem.totalDown; server.totalDown = _serverStatItem.totalDown;
updateFunc_(server); _updateFunc(server);
} }
} }
} }
var sleep = config_.statisticsFreshRate < 1 ? 1 : config_.statisticsFreshRate; var sleep = config_.guiItem.statisticsFreshRate < 1 ? 1 : config_.guiItem.statisticsFreshRate;
Thread.Sleep(1000 * sleep); Thread.Sleep(1000 * sleep);
channel_.ConnectAsync(); await _channel.ConnectAsync();
} }
catch catch
{ {
@@ -134,6 +134,8 @@ namespace v2rayN.Handler
private void Init() private void Init()
{ {
SqliteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
long ticks = DateTime.Now.Date.Ticks; long ticks = DateTime.Now.Date.Ticks;
SqliteHelper.Instance.Execute($"update ServerStatItem set todayUp = 0,todayDown=0,dateNow={ticks} where dateNow<>{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, todayDown = 0,
dateNow = ticks dateNow = ticks
}; };
_ = SqliteHelper.Instance.Replacesync(_serverStatItem); SqliteHelper.Instance.Replace(_serverStatItem);
_lstServerStat.Add(_serverStatItem); _lstServerStat.Add(_serverStatItem);
} }
} }
@@ -180,7 +182,6 @@ namespace v2rayN.Handler
server = new(); server = new();
try try
{ {
foreach (Stat stat in source) foreach (Stat stat in source)
{ {
string name = stat.Name; string name = stat.Name;
@@ -229,7 +230,7 @@ namespace v2rayN.Handler
try try
{ {
// TCP stack please do me a favor // TCP stack please do me a favor
TcpListener l = new TcpListener(IPAddress.Loopback, 0); TcpListener l = new(IPAddress.Loopback, 0);
l.Start(); l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port; int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop(); l.Stop();
@@ -243,4 +244,4 @@ namespace v2rayN.Handler
} }
} }
} }
} }

View File

@@ -20,9 +20,9 @@ namespace v2rayN.Handler
// <proxy-server><CR-LF> // <proxy-server><CR-LF>
// <bypass-list><CR-LF> // <bypass-list><CR-LF>
// <pac-url> // <pac-url>
private static SysproxyConfig _userSettings = null; private static SysproxyConfig? _userSettings = null;
enum RET_ERRORS : int private enum RET_ERRORS : int
{ {
RET_NO_ERROR = 0, RET_NO_ERROR = 0,
INVALID_FORMAT = 1, INVALID_FORMAT = 1,
@@ -45,12 +45,11 @@ namespace v2rayN.Handler
} }
} }
public static bool UpdateSysProxy(Config config, bool forceDisable) public static bool UpdateSysProxy(Config config, bool forceDisable)
{ {
var type = config.sysProxyType; var type = config.sysProxyType;
if (forceDisable && type == ESysProxyType.ForcedChange) if (forceDisable && type != ESysProxyType.Unchanged)
{ {
type = ESysProxyType.ForcedClear; type = ESysProxyType.ForcedClear;
} }
@@ -120,7 +119,6 @@ namespace v2rayN.Handler
} }
} }
public static void SetIEProxy(bool global, string strProxy, string strExceptions) public static void SetIEProxy(bool global, string strProxy, string strExceptions)
{ {
string arguments = global string arguments = global
@@ -154,87 +152,81 @@ namespace v2rayN.Handler
// using event to avoid hanging when redirect standard output/error // using event to avoid hanging when redirect standard output/error
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why // ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
// and http://blog.csdn.net/zhangweixing0/article/details/7356841 // and http://blog.csdn.net/zhangweixing0/article/details/7356841
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) using AutoResetEvent outputWaitHandle = new(false);
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) using AutoResetEvent errorWaitHandle = new(false);
using Process process = new();
// Configure the process using the StartInfo properties.
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
// Need to provide encoding info, or output/error strings we got will be wrong.
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
process.StartInfo.CreateNoWindow = true;
StringBuilder output = new(1024);
StringBuilder error = new(1024);
process.OutputDataReceived += (sender, e) =>
{ {
using (Process process = new Process()) if (e.Data == null)
{ {
// Configure the process using the StartInfo properties. outputWaitHandle.Set();
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
// Need to provide encoding info, or output/error strings we got will be wrong.
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
process.StartInfo.CreateNoWindow = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
try
{
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
}
catch (System.ComponentModel.Win32Exception e)
{
// log the arguments
throw new Exception(process.StartInfo.Arguments);
}
string stderr = error.ToString();
string stdout = output.ToString();
int exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
throw new Exception(stderr);
}
//if (arguments == "query")
//{
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
// {
// throw new Exception("failed to query wininet settings");
// }
// _queryStr = stdout;
//}
} }
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
try
{
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
} }
catch (System.ComponentModel.Win32Exception e)
{
// log the arguments
throw new Exception(process.StartInfo.Arguments);
}
string stderr = error.ToString();
string stdout = output.ToString();
int exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
throw new Exception(stderr);
}
//if (arguments == "query")
//{
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
// {
// throw new Exception("failed to query wininet settings");
// }
// _queryStr = stdout;
//}
} }
} }
} }

View File

@@ -3,17 +3,18 @@ using System.IO;
using System.Reactive.Linq; using System.Reactive.Linq;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Base namespace v2rayN.Base
{ {
public sealed class TunHandler public sealed class TunHandler
{ {
private static readonly Lazy<TunHandler> _instance = new Lazy<TunHandler>(() => new()); private static readonly Lazy<TunHandler> _instance = new(() => new());
public static TunHandler Instance => _instance.Value; public static TunHandler Instance => _instance.Value;
private string _tunConfigName = "tunConfig.json"; private string _tunConfigName = "tunConfig.json";
private static Config _config; private static Config _config;
private CoreInfo coreInfo; private CoreInfo coreInfo;
private Process _process; private Process? _process;
private static int _socksPort; private static int _socksPort;
private static bool _needRestart = true; private static bool _needRestart = true;
private static bool _isRunning = false; private static bool _isRunning = false;
@@ -44,7 +45,7 @@ namespace v2rayN.Base
{ {
var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks); var socksPort = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
if (socksPort.Equals(_socksPort) if (socksPort == _socksPort
&& _process != null && _process != null
&& !_process.HasExited) && !_process.HasExited)
{ {
@@ -60,6 +61,7 @@ namespace v2rayN.Base
{ {
return; return;
} }
CoreStartTest();
CoreStart(); CoreStart();
} }
} }
@@ -100,13 +102,41 @@ namespace v2rayN.Base
configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}"); configStr = configStr.Replace("$strict_route$", $"{_config.tunModeItem.strictRoute.ToString().ToLower()}");
configStr = configStr.Replace("$stack$", $"{_config.tunModeItem.stack}"); 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$", $"");
}
else
{
var dtNow = DateTime.Now;
var log_output = $"\"output\": \"{Utils.GetLogPath($"singbox_{dtNow:yyyy-MM-dd}.txt")}\", ";
configStr = configStr.Replace("$log_output$", $"{log_output.Replace(@"\", @"\\")}");
}
//port //port
configStr = configStr.Replace("$socksPort$", $"{_socksPort}"); configStr = configStr.Replace("$socksPort$", $"{_socksPort}");
//dns
string dnsObject = String.Empty;
if (_config.tunModeItem.bypassMode)
{
dnsObject = _config.tunModeItem.directDNS;
}
else
{
dnsObject = _config.tunModeItem.proxyDNS;
}
if (dnsObject.IsNullOrEmpty() || Utils.ParseJson(dnsObject)?.ContainsKey("servers") == false)
{
dnsObject = Utils.GetEmbedText(Global.TunSingboxDNSFileName);
}
configStr = configStr.Replace("$dns_object$", dnsObject);
//exe //exe
List<string> lstDnsExe = new List<string>(); List<string> lstDnsExe = new();
List<string> lstDirectExe = new List<string>(); List<string> lstDirectExe = new();
var coreInfos = LazyConfig.Instance.GetCoreInfos(); var coreInfos = LazyConfig.Instance.GetCoreInfos();
foreach (var it in coreInfos) foreach (var it in coreInfos)
{ {
@@ -118,13 +148,13 @@ namespace v2rayN.Base
{ {
if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box) if (!lstDnsExe.Contains(it2) && it.coreType != ECoreType.sing_box)
{ {
lstDnsExe.Add(it2); //lstDnsExe.Add(it2);
lstDnsExe.Add($"{it2}.exe"); lstDnsExe.Add($"{it2}.exe");
} }
if (!lstDirectExe.Contains(it2)) if (!lstDirectExe.Contains(it2))
{ {
lstDirectExe.Add(it2); //lstDirectExe.Add(it2);
lstDirectExe.Add($"{it2}.exe"); lstDirectExe.Add($"{it2}.exe");
} }
} }
@@ -135,27 +165,44 @@ namespace v2rayN.Base
string strDirect = string.Join("\",\"", lstDirectExe.ToArray()); string strDirect = string.Join("\",\"", lstDirectExe.ToArray());
configStr = configStr.Replace("$directProcessName$", $"\"{strDirect}\""); configStr = configStr.Replace("$directProcessName$", $"\"{strDirect}\"");
if (_config.tunModeItem.bypassMode)
{
//direct ips
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0)
{
var ips = new { outbound = "direct", ip_cidr = _config.tunModeItem.directIP };
configStr = configStr.Replace("$ruleDirectIPs$", "," + Utils.ToJson(ips));
}
//direct process
if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0)
{
var process = new { outbound = "direct", process_name = _config.tunModeItem.directProcess };
configStr = configStr.Replace("$ruleDirectProcess$", "," + Utils.ToJson(process));
}
}
else
{
//proxy ips
if (_config.tunModeItem.proxyIP != null && _config.tunModeItem.proxyIP.Count > 0)
{
var ips = new { outbound = "proxy", ip_cidr = _config.tunModeItem.proxyIP };
configStr = configStr.Replace("$ruleProxyIPs$", "," + Utils.ToJson(ips));
}
//proxy process
if (_config.tunModeItem.proxyProcess != null && _config.tunModeItem.proxyProcess.Count > 0)
{
var process = new { outbound = "proxy", process_name = _config.tunModeItem.proxyProcess };
configStr = configStr.Replace("$ruleProxyProcess$", "," + Utils.ToJson(process));
}
//ips var final = new { outbound = "direct", inbound = "tun-in" };
if (_config.tunModeItem.directIP != null && _config.tunModeItem.directIP.Count > 0) configStr = configStr.Replace("$ruleFinally$", "," + Utils.ToJson(final));
{
var ips = new { outbound = "direct", ip_cidr = _config.tunModeItem.directIP };
configStr = configStr.Replace("$ruleDirectIPs$", "," + Utils.ToJson(ips));
}
else
{
configStr = configStr.Replace("$ruleDirectIPs$", "");
}
//process
if (_config.tunModeItem.directProcess != null && _config.tunModeItem.directProcess.Count > 0)
{
var process = new { outbound = "direct", process_name = _config.tunModeItem.directProcess };
configStr = configStr.Replace("$ruleDirectProcess$", "," + Utils.ToJson(process));
}
else
{
configStr = configStr.Replace("$ruleDirectProcess$", "");
} }
configStr = configStr.Replace("$ruleDirectIPs$", "");
configStr = configStr.Replace("$ruleDirectProcess$", "");
configStr = configStr.Replace("$ruleProxyIPs$", "");
configStr = configStr.Replace("$ruleProxyProcess$", "");
configStr = configStr.Replace("$ruleFinally$", "");
File.WriteAllText(Utils.GetConfigPath(_tunConfigName), configStr); File.WriteAllText(Utils.GetConfigPath(_tunConfigName), configStr);
@@ -172,6 +219,7 @@ namespace v2rayN.Base
KillProcess(_process); KillProcess(_process);
_process.Dispose(); _process.Dispose();
_process = null; _process = null;
_needRestart = true;
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -195,7 +243,8 @@ namespace v2rayN.Base
} }
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.coreType), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
Utils.SaveLog(msg);
} }
return fileName; return fileName;
} }
@@ -205,12 +254,12 @@ namespace v2rayN.Base
try try
{ {
string fileName = CoreFindexe(); string fileName = CoreFindexe();
if (fileName == "") if (Utils.IsNullOrEmpty(fileName))
{ {
return; return;
} }
var showWindow = _config.tunModeItem.showWindow; var showWindow = _config.tunModeItem.showWindow;
Process p = new Process Process p = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
@@ -263,5 +312,47 @@ namespace v2rayN.Base
Utils.SaveLog(ex.Message, ex); Utils.SaveLog(ex.Message, ex);
} }
} }
private int CoreStartTest()
{
Utils.SaveLog("Tun mode configuration file test start");
try
{
string fileName = CoreFindexe();
if (fileName == "")
{
return -1;
}
Process p = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = $"run -c \"{Utils.GetConfigPath(_tunConfigName)}\"",
WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
Verb = "runas",
}
};
p.Start();
if (p.WaitForExit(2000))
{
throw new Exception(p.StandardError.ReadToEnd());
}
KillProcess(p);
return 0;
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
return -1;
}
finally
{
Utils.SaveLog("Tun mode configuration file test end");
}
}
} }
} }

View File

@@ -1,18 +1,20 @@
using Splat; using DynamicData;
using Splat;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Forms; using System.Windows;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx; using v2rayN.Resx;
namespace v2rayN.Handler namespace v2rayN.Handler
{ {
class UpdateHandle internal class UpdateHandle
{ {
Action<bool, string> _updateFunc; private Action<bool, string> _updateFunc;
private Config _config; private Config _config;
public event EventHandler<ResultEventArgs> AbsoluteCompleted; public event EventHandler<ResultEventArgs> AbsoluteCompleted;
@@ -35,51 +37,46 @@ namespace v2rayN.Handler
_updateFunc = update; _updateFunc = update;
var url = string.Empty; var url = string.Empty;
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null) downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
{
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
try try
{
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
fileName = Utils.UrlEncode(fileName);
Process process = new()
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); StartInfo = new ProcessStartInfo
fileName = Utils.UrlEncode(fileName);
Process process = new Process
{ {
StartInfo = new ProcessStartInfo FileName = "v2rayUpgrade.exe",
{ Arguments = $"\"{fileName}\"",
FileName = "v2rayUpgrade.exe", WorkingDirectory = Utils.StartupPath()
Arguments = $"\"{fileName}\"",
WorkingDirectory = Utils.StartupPath()
}
};
process.Start();
if (process.Id > 0)
{
_updateFunc(true, "");
} }
} };
catch (Exception ex) process.Start();
if (process.Id > 0)
{ {
_updateFunc(false, ex.Message); _updateFunc(true, "");
} }
} }
else catch (Exception ex)
{ {
_updateFunc(false, args.Msg); _updateFunc(false, ex.Message);
} }
}; }
downloadHandle.Error += (sender2, args) => else
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.Msg);
}; }
} };
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, args.GetException().Message);
};
AbsoluteCompleted += (sender2, args) => AbsoluteCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -99,43 +96,38 @@ namespace v2rayN.Handler
CheckUpdateAsync(ECoreType.v2rayN, preRelease); CheckUpdateAsync(ECoreType.v2rayN, preRelease);
} }
public void CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease) public void CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
{ {
_config = config; _config = config;
_updateFunc = update; _updateFunc = update;
var url = string.Empty; var url = string.Empty;
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null) downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
{ _updateFunc(false, ResUI.MsgUnpacking);
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(false, ResUI.MsgUnpacking);
try try
{
_updateFunc(true, url);
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
}
}
else
{ {
_updateFunc(false, args.Msg); _updateFunc(true, url);
} }
}; catch (Exception ex)
downloadHandle.Error += (sender2, args) => {
_updateFunc(false, ex.Message);
}
}
else
{ {
_updateFunc(true, args.GetException().Message); _updateFunc(false, args.Msg);
}; }
} };
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(true, args.GetException().Message);
};
AbsoluteCompleted += (sender2, args) => AbsoluteCompleted += (sender2, args) =>
{ {
@@ -155,7 +147,6 @@ namespace v2rayN.Handler
CheckUpdateAsync(type, preRelease); CheckUpdateAsync(type, preRelease);
} }
public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> update) public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> update)
{ {
_config = config; _config = config;
@@ -172,36 +163,22 @@ namespace v2rayN.Handler
Task.Run(async () => 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) foreach (var item in subItem)
{ {
if (item.enabled == false)
{
continue;
}
if (!Utils.IsNullOrEmpty(subId) && item.id != subId)
{
continue;
}
string id = item.id.TrimEx(); string id = item.id.TrimEx();
string url = item.url.TrimEx(); string url = item.url.TrimEx();
string userAgent = item.userAgent.TrimEx(); string userAgent = item.userAgent.TrimEx();
string hashCode = $"{item.remarks}->"; 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}"); //_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
continue; continue;
} }
if (item.enabled == false)
{
_updateFunc(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}");
continue;
}
var downloadHandle = new DownloadHandle(); var downloadHandle = new DownloadHandle();
downloadHandle.Error += (sender2, args) => downloadHandle.Error += (sender2, args) =>
@@ -209,14 +186,67 @@ namespace v2rayN.Handler
_updateFunc(false, $"{hashCode}{args.GetException().Message}"); _updateFunc(false, $"{hashCode}{args.GetException().Message}");
}; };
//idn to idc
url = Utils.GetPunycode(url);
_updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}"); _updateFunc(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}");
var result = await downloadHandle.DownloadStringAsync(url, blProxy, userAgent);
//one url
url = Utils.GetPunycode(url);
//convert
if (!Utils.IsNullOrEmpty(item.convertTarget))
{
var subConvertUrl = string.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
if (!url.Contains("target="))
{
url += string.Format("&target={0}", item.convertTarget);
}
if (!url.Contains("config="))
{
url += string.Format("&config={0}", Global.SubConvertConfig.FirstOrDefault());
}
}
var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent);
if (blProxy && Utils.IsNullOrEmpty(result)) 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.convertTarget) && !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)) if (Utils.IsNullOrEmpty(result))
@@ -226,7 +256,7 @@ namespace v2rayN.Handler
else else
{ {
_updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}"); _updateFunc(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
if (result.Length < 99) if (result!.Length < 99)
{ {
_updateFunc(false, $"{hashCode}{result}"); _updateFunc(false, $"{hashCode}{result}");
} }
@@ -244,67 +274,56 @@ namespace v2rayN.Handler
} }
_updateFunc(false, "-------------------------------------------------------"); _updateFunc(false, "-------------------------------------------------------");
} }
//restore system proxy
if (bSysProxyType)
{
config.sysProxyType = ESysProxyType.ForcedChange;
SysProxyHandle.UpdateSysProxy(config, false);
}
_updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
_updateFunc(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
}); });
} }
public void UpdateGeoFile(string geoName, Config config, Action<bool, string> update) public void UpdateGeoFile(string geoName, Config config, Action<bool, string> update)
{ {
_config = config; _config = config;
_updateFunc = update; _updateFunc = update;
var url = string.Format(Global.geoUrl, geoName); var url = string.Format(Global.geoUrl, geoName);
DownloadHandle downloadHandle = null; DownloadHandle downloadHandle = new();
if (downloadHandle == null) downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
downloadHandle = new DownloadHandle(); if (args.Success)
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) _updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
try
{ {
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName)); string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
if (File.Exists(fileName))
try
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); //Global.coreTypes.ForEach(it =>
if (File.Exists(fileName)) //{
{ // string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
Global.coreTypes.ForEach(it => // File.Copy(fileName, targetPath, true);
{ //});
string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it)); string targetPath = Utils.GetBinPath($"{geoName}.dat");
File.Copy(fileName, targetPath, true); File.Copy(fileName, targetPath, true);
});
File.Delete(fileName); File.Delete(fileName);
//_updateFunc(true, ""); //_updateFunc(true, "");
}
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
} }
} }
else catch (Exception ex)
{ {
_updateFunc(false, args.Msg); _updateFunc(false, ex.Message);
} }
}; }
downloadHandle.Error += (sender2, args) => else
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.Msg);
}; }
} };
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, args.GetException().Message);
};
askToDownload(downloadHandle, url, false); askToDownload(downloadHandle, url, false);
} }
public void RunAvailabilityCheck(Action<bool, string> update) public void RunAvailabilityCheck(Action<bool, string> update)
@@ -351,7 +370,6 @@ namespace v2rayN.Handler
{ {
try try
{ {
var coreInfo = LazyConfig.Instance.GetCoreInfo(type); var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
string filePath = string.Empty; string filePath = string.Empty;
foreach (string name in coreInfo.coreExes) foreach (string name in coreInfo.coreExes)
@@ -372,7 +390,7 @@ namespace v2rayN.Handler
return ""; return "";
} }
Process p = new Process(); using Process p = new();
p.StartInfo.FileName = filePath; p.StartInfo.FileName = filePath;
p.StartInfo.Arguments = coreInfo.versionArg; p.StartInfo.Arguments = coreInfo.versionArg;
p.StartInfo.WorkingDirectory = Utils.StartupPath(); p.StartInfo.WorkingDirectory = Utils.StartupPath();
@@ -392,10 +410,15 @@ namespace v2rayN.Handler
case ECoreType.v2fly_v5: case ECoreType.v2fly_v5:
version = Regex.Match(echo, $"{coreInfo.match} ([0-9.]+) \\(").Groups[1].Value; version = Regex.Match(echo, $"{coreInfo.match} ([0-9.]+) \\(").Groups[1].Value;
break; break;
case ECoreType.clash: case ECoreType.clash:
case ECoreType.clash_meta: case ECoreType.clash_meta:
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value; version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
break; break;
case ECoreType.sing_box:
version = Regex.Match(echo, $"([0-9.]+)").Groups[1].Value;
break;
} }
return version; return version;
} }
@@ -406,6 +429,7 @@ namespace v2rayN.Handler
return ""; return "";
} }
} }
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease) private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease)
{ {
try try
@@ -434,7 +458,22 @@ namespace v2rayN.Handler
{ {
curVersion = "v" + getCoreVersion(type); curVersion = "v" + getCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, curVersion); 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); url = string.Format(coreInfo.coreDownloadUrl64, version, osBit);
break; break;
} }
@@ -443,21 +482,62 @@ namespace v2rayN.Handler
{ {
curVersion = getCoreVersion(type); curVersion = getCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, curVersion); 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:
{
curVersion = "v" + getCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, curVersion);
switch (RuntimeInformation.ProcessArchitecture)
{ {
url = string.Format(coreInfo.coreDownloadUrl32, version); 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; break;
} }
case ECoreType.v2rayN: case ECoreType.v2rayN:
{ {
curVersion = FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString(); curVersion = FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString();
message = string.Format(ResUI.IsLatestN, curVersion); message = string.Format(ResUI.IsLatestN, curVersion);
url = string.Format(coreInfo.coreDownloadUrl64, version); 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; break;
} }
default: default:
@@ -495,7 +575,7 @@ namespace v2rayN.Handler
bool blDownload = false; bool blDownload = false;
if (blAsk) if (blAsk)
{ {
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == DialogResult.Yes) if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes)
{ {
blDownload = true; blDownload = true;
} }
@@ -509,6 +589,7 @@ namespace v2rayN.Handler
downloadHandle.DownloadFileAsync(url, true, 600); downloadHandle.DownloadFileAsync(url, true, 600);
} }
} }
#endregion
#endregion private
} }
} }

View File

@@ -6,9 +6,10 @@
{ {
get; set; get; set;
} }
public string Text public string Text
{ {
get; set; get; set;
} }
} }
} }

View File

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

View File

@@ -1,7 +1,38 @@
using System.Windows.Forms; using System.Windows.Input;
namespace v2rayN.Mode namespace v2rayN.Mode
{ {
[Serializable]
public class CoreBasicItem
{
/// <summary>
/// 允许日志
/// </summary>
public bool logEnabled { get; set; }
/// <summary>
/// 日志等级
/// </summary>
public string loglevel { get; set; }
/// <summary>
/// 允许Mux多路复用
/// </summary>
public bool muxEnabled { get; set; }
/// <summary>
/// 是否允许不安全连接
/// </summary>
public bool defAllowInsecure { get; set; }
public string defFingerprint { get; set; }
/// <summary>
/// 默认用户代理
/// </summary>
public string defUserAgent { get; set; }
}
[Serializable] [Serializable]
public class InItem public class InItem
{ {
@@ -21,7 +52,6 @@ namespace v2rayN.Mode
public string user { get; set; } public string user { get; set; }
public string pass { get; set; } public string pass { get; set; }
} }
[Serializable] [Serializable]
@@ -51,6 +81,32 @@ namespace v2rayN.Mode
public int initial_windows_size { get; set; } public int initial_windows_size { get; set; }
} }
[Serializable]
public class GUIItem
{
public bool autoRun { get; set; }
public bool enableStatistics { get; set; }
public int statisticsFreshRate { get; set; }
public bool keepOlderDedupl { get; set; }
public bool ignoreGeoUpdateCore { get; set; } = true;
public int autoUpdateInterval { get; set; } = 10;
public bool checkPreReleaseUpdate { get; set; } = false;
public bool enableSecurityProtocolTls13 { get; set; }
public int trayMenuServersLimit { get; set; } = 20;
public bool enableHWA { get; set; } = false;
public bool enableLog { get; set; } = true;
}
[Serializable] [Serializable]
public class UIItem public class UIItem
{ {
@@ -63,18 +119,20 @@ namespace v2rayN.Mode
public string? colorPrimaryName { get; set; } public string? colorPrimaryName { get; set; }
public string currentLanguage { get; set; } public string currentLanguage { get; set; }
public string currentFontFamily { get; set; } public string currentFontFamily { get; set; }
public int currentFontSize { get; set; }
public bool enableDragDropSort { get; set; } public bool enableDragDropSort { get; set; }
public bool doubleClick2Activate { get; set; } public bool doubleClick2Activate { get; set; }
public bool autoHideStartup { get; set; } = true; public bool autoHideStartup { get; set; } = true;
public Dictionary<string, int> mainLvColWidth { get; set; } public string mainMsgFilter { get; set; }
public bool showTrayTip { get; set; }
public List<ColumnItem> mainColumnItem { get; set; }
} }
[Serializable] [Serializable]
public class ConstItem public class ConstItem
{ {
public string speedTestUrl { get; set; }
public string speedPingTestUrl { get; set; }
public string defIEProxyExceptions { get; set; } public string defIEProxyExceptions { get; set; }
public string subConvertUrl { get; set; } = string.Empty;
} }
[Serializable] [Serializable]
@@ -88,8 +146,7 @@ namespace v2rayN.Mode
public bool Shift { get; set; } public bool Shift { get; set; }
public Keys? KeyCode { get; set; } public Key? KeyCode { get; set; }
} }
[Serializable] [Serializable]
@@ -105,12 +162,46 @@ namespace v2rayN.Mode
{ {
public bool enableTun { get; set; } public bool enableTun { get; set; }
public bool showWindow { get; set; } public bool showWindow { get; set; }
public bool enabledLog { get; set; }
public bool strictRoute { get; set; } public bool strictRoute { get; set; }
public string stack { get; set; } public string stack { get; set; }
public int mtu { get; set; } public int mtu { get; set; }
public string customTemplate { get; set; } public string customTemplate { get; set; }
public bool bypassMode { get; set; } = true;
public List<string> directIP { get; set; } public List<string> directIP { get; set; }
public List<string> directProcess { get; set; } public List<string> directProcess { get; set; }
public string directDNS { get; set; }
public List<string> proxyIP { get; set; }
public List<string> proxyProcess { get; set; }
public string proxyDNS { get; set; }
} }
}
[Serializable]
public class SpeedTestItem
{
public int speedTestTimeout { get; set; }
public string speedTestUrl { get; set; }
public string speedPingTestUrl { get; set; }
}
[Serializable]
public class RoutingBasicItem
{
/// <summary>
/// 域名解析策略
/// </summary>
public string domainStrategy { get; set; }
public string domainMatcher { get; set; }
public string routingIndexId { get; set; }
public bool enableRoutingAdvanced { get; set; }
}
[Serializable]
public class ColumnItem
{
public string Name { get; set; }
public int Width { get; set; }
public int Index { get; set; }
}
}

View File

@@ -35,7 +35,7 @@
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ESysProxyType sysProxyType public ESysProxyType sysProxyType
{ {
@@ -97,14 +97,17 @@
{ {
get; set; get; set;
} }
public string domainMatcher public string domainMatcher
{ {
get; set; get; set;
} }
public int routingIndex public int routingIndex
{ {
get; set; get; set;
} }
public bool enableRoutingAdvanced public bool enableRoutingAdvanced
{ {
get; set; get; set;
@@ -122,6 +125,7 @@
{ {
get; set; get; set;
} }
public string systemProxyAdvancedProtocol { get; set; } public string systemProxyAdvancedProtocol { get; set; }
public int autoUpdateInterval { get; set; } = 0; public int autoUpdateInterval { get; set; } = 0;
@@ -137,7 +141,7 @@
public int trayMenuServersLimit { get; set; } public int trayMenuServersLimit { get; set; }
#endregion #endregion property
#region other entities #region other entities
@@ -172,6 +176,7 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// UI /// UI
/// </summary> /// </summary>
@@ -179,6 +184,7 @@
{ {
get; set; get; set;
} }
public List<RoutingItemOld> routings public List<RoutingItemOld> routings
{ {
get; set; get; set;
@@ -194,14 +200,12 @@
get; set; get; set;
} }
public List<CoreTypeItem> coreTypeItem public List<CoreTypeItem> coreTypeItem
{ {
get; set; get; set;
} }
#endregion #endregion other entities
} }
[Serializable] [Serializable]
@@ -231,7 +235,6 @@
groupId = string.Empty; groupId = string.Empty;
} }
public string indexId public string indexId
{ {
get; set; get; set;
@@ -265,6 +268,7 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// 远程服务器端口 /// 远程服务器端口
/// </summary> /// </summary>
@@ -272,6 +276,7 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// 远程服务器ID /// 远程服务器ID
/// </summary> /// </summary>
@@ -279,6 +284,7 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// 远程服务器额外ID /// 远程服务器额外ID
/// </summary> /// </summary>
@@ -286,6 +292,7 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// 本地安全策略 /// 本地安全策略
/// </summary> /// </summary>
@@ -293,6 +300,7 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// tcp,kcp,ws,h2,quic /// tcp,kcp,ws,h2,quic
/// </summary> /// </summary>
@@ -300,8 +308,9 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// 备注或别名 ///
/// </summary> /// </summary>
public string remarks public string remarks
{ {
@@ -349,7 +358,7 @@
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string testResult public string testResult
{ {
@@ -371,6 +380,7 @@
{ {
get; set; get; set;
} }
/// <summary> /// <summary>
/// tls sni /// tls sni
/// </summary> /// </summary>
@@ -404,23 +414,27 @@
{ {
get; set; get; set;
} }
public string url public string url
{ {
get; set; get; set;
} }
public List<RulesItem> rules public List<RulesItem> rules
{ {
get; set; get; set;
} }
public bool enabled { get; set; } = true; public bool enabled { get; set; } = true;
public bool locked public bool locked
{ {
get; set; get; set;
} }
public string customIcon public string customIcon
{ {
get; set; get; set;
} }
} }
} }

View File

@@ -17,10 +17,11 @@
public string coreDownloadUrl64 { get; set; } public string coreDownloadUrl64 { get; set; }
public string coreDownloadUrlArm64 { get; set; }
public string match { get; set; } public string match { get; set; }
public string versionArg { get; set; } public string versionArg { get; set; }
public bool redirectInfo { get; set; } public bool redirectInfo { get; set; }
} }
} }

View File

@@ -1,5 +1,4 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
public enum EConfigType public enum EConfigType
{ {
@@ -10,4 +9,4 @@ namespace v2rayN.Mode
VLESS = 5, VLESS = 5,
Trojan = 6 Trojan = 6
} }
} }

View File

@@ -1,5 +1,4 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
public enum ECoreType public enum ECoreType
{ {
@@ -15,4 +14,4 @@ namespace v2rayN.Mode
sing_box = 24, sing_box = 24,
v2rayN = 99 v2rayN = 99
} }
} }

View File

@@ -1,5 +1,4 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
public enum EGlobalHotkey public enum EGlobalHotkey
{ {
@@ -9,4 +8,4 @@ namespace v2rayN.Mode
SystemProxyUnchanged = 3, SystemProxyUnchanged = 3,
SystemProxyPac = 4, SystemProxyPac = 4,
} }
} }

View File

@@ -1,5 +1,4 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
public enum EMove public enum EMove
{ {
@@ -9,4 +8,4 @@ namespace v2rayN.Mode
Bottom = 4, Bottom = 4,
Position = 5 Position = 5
} }
} }

View File

@@ -1,5 +1,4 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
public enum EServerColName public enum EServerColName
{ {
@@ -12,8 +11,8 @@ namespace v2rayN.Mode
network, network,
streamSecurity, streamSecurity,
subRemarks, subRemarks,
delay, delayVal,
speed, speedVal,
todayDown, todayDown,
todayUp, todayUp,

View File

@@ -1,5 +1,4 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
public enum ESpeedActionType public enum ESpeedActionType
{ {
@@ -9,4 +8,4 @@ namespace v2rayN.Mode
Speedtest, Speedtest,
Mixedtest Mixedtest
} }
} }

View File

@@ -1,5 +1,4 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
public enum ESysProxyType public enum ESysProxyType
{ {
@@ -8,4 +7,4 @@ namespace v2rayN.Mode
Unchanged = 2, Unchanged = 2,
Pac = 3 Pac = 3
} }
} }

View File

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

View File

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

View File

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

View File

@@ -5,12 +5,14 @@
{ {
public bool isActive { get; set; } public bool isActive { get; set; }
public string subRemarks { get; set; } public string subRemarks { get; set; }
public int delay { get; set; }
public decimal speed { get; set; }
public int sort { get; set; }
public string delayVal { get; set; } public string delayVal { get; set; }
public string speedVal { get; set; } public string speedVal { get; set; }
public string todayUp { get; set; } public string todayUp { get; set; }
public string todayDown { get; set; } public string todayDown { get; set; }
public string totalUp { get; set; } public string totalUp { get; set; }
public string totalDown { get; set; } public string totalDown { get; set; }
} }
} }

View File

@@ -7,6 +7,7 @@ namespace v2rayN.Mode
{ {
[PrimaryKey] [PrimaryKey]
public string id { get; set; } public string id { get; set; }
public string remarks { get; set; } public string remarks { get; set; }
public string url { get; set; } public string url { get; set; }
public string ruleSet { get; set; } public string ruleSet { get; set; }
@@ -15,6 +16,6 @@ namespace v2rayN.Mode
public bool locked { get; set; } public bool locked { get; set; }
public string customIcon { get; set; } public string customIcon { get; set; }
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
public int sort { get; set; }
} }
} }

View File

@@ -4,6 +4,5 @@
public class RoutingItemModel : RoutingItem public class RoutingItemModel : RoutingItem
{ {
public bool isActive { get; set; } public bool isActive { get; set; }
} }
} }

View File

@@ -19,7 +19,5 @@
public List<string> protocol { get; set; } public List<string> protocol { get; set; }
public bool enabled { get; set; } = true; public bool enabled { get; set; } = true;
} }
}
}

View File

@@ -10,6 +10,5 @@
public string domains { get; set; } public string domains { get; set; }
public string protocols { get; set; } public string protocols { get; set; }
} }
} }

View File

@@ -1,23 +1,26 @@
namespace v2rayN.Mode namespace v2rayN.Mode
{ {
[Serializable] [Serializable]
class ServerSpeedItem : ServerStatItem internal class ServerSpeedItem : ServerStatItem
{ {
public long proxyUp public long proxyUp
{ {
get; set; get; set;
} }
public long proxyDown public long proxyDown
{ {
get; set; get; set;
} }
public long directUp public long directUp
{ {
get; set; get; set;
} }
public long directDown public long directDown
{ {
get; set; get; set;
} }
} }
} }

View File

@@ -10,25 +10,30 @@ namespace v2rayN.Mode
{ {
get; set; get; set;
} }
public long totalUp public long totalUp
{ {
get; set; get; set;
} }
public long totalDown public long totalDown
{ {
get; set; get; set;
} }
public long todayUp public long todayUp
{ {
get; set; get; set;
} }
public long todayDown public long todayDown
{ {
get; set; get; set;
} }
public long dateNow public long dateNow
{ {
get; set; get; set;
} }
} }
} }

View File

@@ -1,7 +1,7 @@
namespace v2rayN.Mode namespace v2rayN.Mode
{ {
[Serializable] [Serializable]
class ServerTestItem internal class ServerTestItem
{ {
public string indexId { get; set; } public string indexId { get; set; }
public string address { get; set; } public string address { get; set; }
@@ -10,4 +10,4 @@
public bool allowTest { get; set; } public bool allowTest { get; set; }
public int delay { get; set; } public int delay { get; set; }
} }
} }

View File

@@ -15,5 +15,4 @@
public string password { get; set; } public string password { get; set; }
public string plugin { get; set; } public string plugin { get; set; }
} }
}
}

View File

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

View File

@@ -1,7 +1,6 @@
 namespace v2rayN.Mode
namespace v2rayN.Mode
{ {
class SysproxyConfig internal class SysproxyConfig
{ {
public bool UserSettingsRecorded; public bool UserSettingsRecorded;
public string Flags; public string Flags;
@@ -18,4 +17,4 @@ namespace v2rayN.Mode
PacUrl = ""; PacUrl = "";
} }
} }
} }

View File

@@ -12,10 +12,12 @@ namespace v2rayN.Mode
/// 日志配置 /// 日志配置
/// </summary> /// </summary>
public Log log { get; set; } public Log log { get; set; }
/// <summary> /// <summary>
/// 传入连接配置 /// 传入连接配置
/// </summary> /// </summary>
public List<Inbounds> inbounds { get; set; } public List<Inbounds> inbounds { get; set; }
/// <summary> /// <summary>
/// 传出连接配置 /// 传出连接配置
/// </summary> /// </summary>
@@ -36,13 +38,15 @@ namespace v2rayN.Mode
/// DNS 配置 /// DNS 配置
/// </summary> /// </summary>
public object dns { get; set; } public object dns { get; set; }
/// <summary> /// <summary>
/// 路由配置 /// 路由配置
/// </summary> /// </summary>
public Routing routing { get; set; } public Routing routing { get; set; }
} }
public class Stats { }; public class Stats
{ };
public class API public class API
{ {
@@ -64,15 +68,17 @@ namespace v2rayN.Mode
public class Log public class Log
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string access { get; set; } public string access { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string error { get; set; } public string error { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string loglevel { get; set; } public string loglevel { get; set; }
} }
@@ -80,46 +86,52 @@ namespace v2rayN.Mode
public class Inbounds public class Inbounds
{ {
public string tag { get; set; } public string tag { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string listen { get; set; } public string listen { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string protocol { get; set; } public string protocol { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Sniffing sniffing { get; set; } public Sniffing sniffing { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Inboundsettings settings { get; set; } public Inboundsettings settings { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public StreamSettings streamSettings { get; set; } public StreamSettings streamSettings { get; set; }
} }
public class Inboundsettings public class Inboundsettings
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string auth { get; set; } public string auth { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool udp { get; set; } public bool udp { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string ip { get; set; } public string ip { get; set; }
@@ -129,11 +141,10 @@ namespace v2rayN.Mode
public string address { get; set; } public string address { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<UsersItem> clients { get; set; } public List<UsersItem> clients { get; set; }
/// <summary> /// <summary>
/// VLESS /// VLESS
/// </summary> /// </summary>
@@ -147,19 +158,22 @@ namespace v2rayN.Mode
public class UsersItem public class UsersItem
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string id { get; set; } public string id { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int alterId { get; set; } public int alterId { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string email { get; set; } public string email { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string security { get; set; } public string security { get; set; }
@@ -173,6 +187,7 @@ namespace v2rayN.Mode
/// </summary> /// </summary>
public string flow { get; set; } public string flow { get; set; }
} }
public class Sniffing public class Sniffing
{ {
public bool enabled { get; set; } public bool enabled { get; set; }
@@ -186,20 +201,24 @@ namespace v2rayN.Mode
/// 默认值agentout /// 默认值agentout
/// </summary> /// </summary>
public string tag { get; set; } public string tag { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string protocol { get; set; } public string protocol { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Outboundsettings settings { get; set; } public Outboundsettings settings { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public StreamSettings streamSettings { get; set; } public StreamSettings streamSettings { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Mux mux { get; set; } public Mux mux { get; set; }
} }
@@ -207,26 +226,27 @@ namespace v2rayN.Mode
public class Outboundsettings public class Outboundsettings
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<VnextItem> vnext { get; set; } public List<VnextItem> vnext { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<ServersItem> servers { get; set; } public List<ServersItem> servers { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Response response { get; set; } public Response response { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int? userLevel { get; set; } public int? userLevel { get; set; }
} }
@@ -234,46 +254,55 @@ namespace v2rayN.Mode
public class VnextItem public class VnextItem
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string address { get; set; } public string address { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<UsersItem> users { get; set; } public List<UsersItem> users { get; set; }
} }
public class ServersItem public class ServersItem
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string email { get; set; } public string email { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string address { get; set; } public string address { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string method { get; set; } public string method { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool ota { get; set; } public bool ota { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string password { get; set; } public string password { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int level { get; set; } public int level { get; set; }
@@ -283,7 +312,7 @@ namespace v2rayN.Mode
public string flow { get; set; } public string flow { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<SocksUsersItem> users { get; set; } public List<SocksUsersItem> users { get; set; }
} }
@@ -291,29 +320,30 @@ namespace v2rayN.Mode
public class SocksUsersItem public class SocksUsersItem
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string user { get; set; } public string user { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string pass { get; set; } public string pass { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int level { get; set; } public int level { get; set; }
} }
public class Mux public class Mux
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool enabled { get; set; } public bool enabled { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int concurrency { get; set; } public int concurrency { get; set; }
} }
@@ -321,7 +351,7 @@ namespace v2rayN.Mode
public class Response public class Response
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string type { get; set; } public string type { get; set; }
} }
@@ -329,7 +359,7 @@ namespace v2rayN.Mode
public class Dns public class Dns
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<string> servers { get; set; } public List<string> servers { get; set; }
} }
@@ -337,15 +367,17 @@ namespace v2rayN.Mode
public class Routing public class Routing
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string domainMatcher { get; set; } public string domainMatcher { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<RulesItem> rules { get; set; } public List<RulesItem> rules { get; set; }
} }
@@ -353,16 +385,17 @@ namespace v2rayN.Mode
public class StreamSettings public class StreamSettings
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string network { get; set; } public string network { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string security { get; set; } public string security { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public TlsSettings tlsSettings { get; set; } public TlsSettings tlsSettings { get; set; }
@@ -370,14 +403,17 @@ namespace v2rayN.Mode
/// Tcp传输额外设置 /// Tcp传输额外设置
/// </summary> /// </summary>
public TcpSettings tcpSettings { get; set; } public TcpSettings tcpSettings { get; set; }
/// <summary> /// <summary>
/// Kcp传输额外设置 /// Kcp传输额外设置
/// </summary> /// </summary>
public KcpSettings kcpSettings { get; set; } public KcpSettings kcpSettings { get; set; }
/// <summary> /// <summary>
/// ws传输额外设置 /// ws传输额外设置
/// </summary> /// </summary>
public WsSettings wsSettings { get; set; } public WsSettings wsSettings { get; set; }
/// <summary> /// <summary>
/// h2传输额外设置 /// h2传输额外设置
/// </summary> /// </summary>
@@ -389,14 +425,14 @@ namespace v2rayN.Mode
public QuicSettings quicSettings { get; set; } public QuicSettings quicSettings { get; set; }
/// <summary> /// <summary>
/// VLESS xtls /// VLESS only
/// </summary> /// </summary>
public TlsSettings xtlsSettings { get; set; } public TlsSettings realitySettings { get; set; }
/// <summary> /// <summary>
/// grpc /// grpc
/// </summary> /// </summary>
public GrpcSettings grpcSettings { get; set; } public GrpcSettings grpcSettings { get; set; }
} }
public class TlsSettings public class TlsSettings
@@ -404,25 +440,24 @@ namespace v2rayN.Mode
/// <summary> /// <summary>
/// 是否允许不安全连接(用于客户端) /// 是否允许不安全连接(用于客户端)
/// </summary> /// </summary>
public bool allowInsecure { get; set; } public bool? allowInsecure { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string serverName { get; set; } public string? serverName { get; set; }
/// <summary>
///
/// </summary>
public List<string> alpn
{
get; set;
}
/// <summary> /// <summary>
/// "chrome" | "firefox" | "safari" | "randomized" ///
/// </summary> /// </summary>
public string fingerprint { get; set; } public List<string>? alpn { 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; }
} }
public class TcpSettings public class TcpSettings
@@ -439,10 +474,12 @@ namespace v2rayN.Mode
/// 伪装 /// 伪装
/// </summary> /// </summary>
public string type { get; set; } public string type { get; set; }
/// <summary> /// <summary>
/// 结构复杂,直接存起来 /// 结构复杂,直接存起来
/// </summary> /// </summary>
public object request { get; set; } public object request { get; set; }
/// <summary> /// <summary>
/// 结构复杂,直接存起来 /// 结构复杂,直接存起来
/// </summary> /// </summary>
@@ -452,39 +489,47 @@ namespace v2rayN.Mode
public class KcpSettings public class KcpSettings
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int mtu { get; set; } public int mtu { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int tti { get; set; } public int tti { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int uplinkCapacity { get; set; } public int uplinkCapacity { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int downlinkCapacity { get; set; } public int downlinkCapacity { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool congestion { get; set; } public bool congestion { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int readBufferSize { get; set; } public int readBufferSize { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int writeBufferSize { get; set; } public int writeBufferSize { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Header header { get; set; } public Header header { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string seed { get; set; } public string seed { get; set; }
} }
@@ -492,19 +537,20 @@ namespace v2rayN.Mode
public class WsSettings public class WsSettings
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string path { get; set; } public string path { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Headers headers { get; set; } public Headers headers { get; set; }
} }
public class Headers public class Headers
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Host { get; set; } public string Host { get; set; }
@@ -518,30 +564,30 @@ namespace v2rayN.Mode
public class HttpSettings public class HttpSettings
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string path { get; set; } public string path { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<string> host { get; set; } public List<string> host { get; set; }
} }
public class QuicSettings public class QuicSettings
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string security { get; set; } public string security { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string key { get; set; } public string key { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public Header header { get; set; } public Header header { get; set; }
} }
@@ -559,12 +605,13 @@ namespace v2rayN.Mode
public class AccountsItem public class AccountsItem
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string user { get; set; } public string user { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string pass { get; set; } public string pass { get; set; }
} }
} }

View File

@@ -6,7 +6,7 @@
public class V2rayTcpRequest public class V2rayTcpRequest
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public RequestHeaders headers { get; set; } public RequestHeaders headers { get; set; }
} }
@@ -14,10 +14,8 @@
public class RequestHeaders public class RequestHeaders
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<string> Host { get; set; } public List<string> Host { get; set; }
} }
}
}

View File

@@ -4,69 +4,81 @@
/// https://github.com/2dust/v2rayN/wiki/ /// https://github.com/2dust/v2rayN/wiki/
/// </summary> /// </summary>
[Serializable] [Serializable]
class VmessQRCode internal class VmessQRCode
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string v { get; set; } = string.Empty; public string v { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string ps { get; set; } = string.Empty; public string ps { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string add { get; set; } = string.Empty; public string add { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string port { get; set; } = string.Empty; public string port { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string id { get; set; } = string.Empty; public string id { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string aid { get; set; } = string.Empty; public string aid { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string scy { get; set; } = string.Empty; public string scy { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string net { get; set; } = string.Empty; public string net { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string type { get; set; } = string.Empty; public string type { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string host { get; set; } = string.Empty; public string host { get; set; } = string.Empty;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string path { get; set; } = string.Empty; public string path { get; set; } = string.Empty;
/// <summary> /// <summary>
/// TLS /// TLS
/// </summary> /// </summary>
public string tls { get; set; } = string.Empty; public string tls { get; set; } = string.Empty;
/// <summary> /// <summary>
/// TLS SNI /// TLS SNI
/// </summary> /// </summary>
public string sni { get; set; } = string.Empty; public string sni { get; set; } = string.Empty;
/// <summary> /// <summary>
/// TLS alpn /// TLS alpn
/// </summary> /// </summary>
public string alpn { get; set; } = string.Empty; public string alpn { get; set; } = string.Empty;
/// <summary> /// <summary>
/// TLS fingerprint /// TLS fingerprint
/// </summary> /// </summary>
public string fp { get; set; } = string.Empty; public string fp { get; set; } = string.Empty;
} }
} }

View File

@@ -70,7 +70,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 All servers 的本地化字符串。 /// 查找类似 All 的本地化字符串。
/// </summary> /// </summary>
public static string AllGroupServers { public static string AllGroupServers {
get { get {
@@ -367,11 +367,29 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Alias 的本地化字符串。 /// 查找类似 Automatic update interval(minutes) 的本地化字符串。
/// </summary> /// </summary>
public static string LvAlias { public static string LvAutoUpdateInterval {
get { get {
return ResourceManager.GetString("LvAlias", resourceCulture); return ResourceManager.GetString("LvAutoUpdateInterval", resourceCulture);
}
}
/// <summary>
/// 查找类似 Convert target type 的本地化字符串。
/// </summary>
public static string LvConvertTarget {
get {
return ResourceManager.GetString("LvConvertTarget", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please leave blank if no conversion is required 的本地化字符串。
/// </summary>
public static string LvConvertTargetTip {
get {
return ResourceManager.GetString("LvConvertTargetTip", resourceCulture);
} }
} }
@@ -420,6 +438,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 More urls, separated by commas;Subscription conversion will be invalid 的本地化字符串。
/// </summary>
public static string LvMoreUrl {
get {
return ResourceManager.GetString("LvMoreUrl", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Port 的本地化字符串。 /// 查找类似 Port 的本地化字符串。
/// </summary> /// </summary>
@@ -474,15 +501,6 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Test Results 的本地化字符串。
/// </summary>
public static string LvTestResults {
get {
return ResourceManager.GetString("LvTestResults", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Speed(M/s) 的本地化字符串。 /// 查找类似 Speed(M/s) 的本地化字符串。
/// </summary> /// </summary>
@@ -564,15 +582,6 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Medium 的本地化字符串。
/// </summary>
public static string MediumFresh {
get {
return ResourceManager.GetString("MediumFresh", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Add a custom configuration server 的本地化字符串。 /// 查找类似 Add a custom configuration server 的本地化字符串。
/// </summary> /// </summary>
@@ -790,7 +799,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 One-click test Latency and speed (Ctrl+E) 的本地化字符串。 /// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
/// </summary> /// </summary>
public static string menuMixedTestServer { public static string menuMixedTestServer {
get { get {
@@ -816,6 +825,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Move up and down 的本地化字符串。
/// </summary>
public static string menuMoveTo {
get {
return ResourceManager.GetString("menuMoveTo", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Move to group 的本地化字符串。 /// 查找类似 Move to group 的本地化字符串。
/// </summary> /// </summary>
@@ -924,6 +942,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Reboot as administrator 的本地化字符串。
/// </summary>
public static string menuRebootAsAdmin {
get {
return ResourceManager.GetString("menuRebootAsAdmin", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Reload 的本地化字符串。 /// 查找类似 Reload 的本地化字符串。
/// </summary> /// </summary>
@@ -1033,7 +1060,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Rule Setting 的本地化字符串。 /// 查找类似 Rule Settings 的本地化字符串。
/// </summary> /// </summary>
public static string menuRoutingRuleSetting { public static string menuRoutingRuleSetting {
get { get {
@@ -1114,7 +1141,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Setting 的本地化字符串。 /// 查找类似 Settings 的本地化字符串。
/// </summary> /// </summary>
public static string menuSetting { public static string menuSetting {
get { get {
@@ -1204,7 +1231,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Subscription group Setting 的本地化字符串。 /// 查找类似 Subscription group Settings 的本地化字符串。
/// </summary> /// </summary>
public static string menuSubSetting { public static string menuSubSetting {
get { get {
@@ -1375,7 +1402,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Please fill in the address (Url) 的本地化字符串。 /// 查找类似 Please fill in the Url 的本地化字符串。
/// </summary> /// </summary>
public static string MsgNeedUrl { public static string MsgNeedUrl {
get { get {
@@ -1392,24 +1419,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> /// <summary>
/// 查找类似 Resolve {0} successfully 的本地化字符串。 /// 查找类似 Resolve {0} successfully 的本地化字符串。
/// </summary> /// </summary>
@@ -1420,7 +1429,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Servers Filter 的本地化字符串。 /// 查找类似 Servers Filter, press Enter to execute 的本地化字符串。
/// </summary> /// </summary>
public static string MsgServerTitle { public static string MsgServerTitle {
get { get {
@@ -1429,11 +1438,11 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Simplify PAC Success 的本地化字符串。 /// 查找类似 Updates are not enabled, skip this subscription 的本地化字符串。
/// </summary> /// </summary>
public static string MsgSimplifyPAC { public static string MsgSkipSubscriptionUpdate {
get { get {
return ResourceManager.GetString("MsgSimplifyPAC", resourceCulture); return ResourceManager.GetString("MsgSkipSubscriptionUpdate", resourceCulture);
} }
} }
@@ -1455,15 +1464,6 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Start updating PAC... 的本地化字符串。
/// </summary>
public static string MsgStartUpdatingPAC {
get {
return ResourceManager.GetString("MsgStartUpdatingPAC", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Invalid subscription content 的本地化字符串。 /// 查找类似 Invalid subscription content 的本地化字符串。
/// </summary> /// </summary>
@@ -1518,24 +1518,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> /// <summary>
/// 查找类似 Non-VMess or ss protocol 的本地化字符串。 /// 查找类似 Non-VMess or ss protocol 的本地化字符串。
/// </summary> /// </summary>
@@ -1644,15 +1626,6 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Fast 的本地化字符串。
/// </summary>
public static string QuickFresh {
get {
return ResourceManager.GetString("QuickFresh", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Global hotkey {0} registered failed, reason {1} 的本地化字符串。 /// 查找类似 Global hotkey {0} registered failed, reason {1} 的本地化字符串。
/// </summary> /// </summary>
@@ -1735,20 +1708,11 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Slow 的本地化字符串。 /// 查找类似 {0}:{1}/s↑ | {2}/s↓ 的本地化字符串。
/// </summary> /// </summary>
public static string SlowFresh { public static string SpeedDisplayText {
get { get {
return ResourceManager.GetString("SlowFresh", resourceCulture); return ResourceManager.GetString("SpeedDisplayText", 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);
} }
} }
@@ -1780,11 +1744,11 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 PAC failed to start. Please run this program as Administrator. 的本地化字符串。 /// 查找类似 Waiting for testing 的本地化字符串。
/// </summary> /// </summary>
public static string StartPacFailed { public static string SpeedtestingWait {
get { get {
return ResourceManager.GetString("StartPacFailed", resourceCulture); return ResourceManager.GetString("SpeedtestingWait", resourceCulture);
} }
} }
@@ -2042,7 +2006,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 GlobalHotkey Setting 的本地化字符串。 /// 查找类似 GlobalHotkey Settings 的本地化字符串。
/// </summary> /// </summary>
public static string TbGlobalHotkeySetting { public static string TbGlobalHotkeySetting {
get { get {
@@ -2158,6 +2122,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 PublicKey 的本地化字符串。
/// </summary>
public static string TbPublicKey {
get {
return ResourceManager.GetString("TbPublicKey", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Alias (remarks) 的本地化字符串。 /// 查找类似 Alias (remarks) 的本地化字符串。
/// </summary> /// </summary>
@@ -2311,24 +2284,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> /// <summary>
/// 查找类似 Automatic update interval of and Geo (hours) 的本地化字符串。 /// 查找类似 Automatic update interval of and Geo (hours) 的本地化字符串。
/// </summary> /// </summary>
@@ -2402,7 +2357,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Copy the font TTF file to the directory Resources\Fonts, restart the settings 的本地化字符串。 /// 查找类似 Copy the font TTF file to the directory guiFonts, restart the settings 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsCurrentFontFamilyTip { public static string TbSettingsCurrentFontFamilyTip {
get { get {
@@ -2491,6 +2446,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Enable hardware acceleration(Require restart) 的本地化字符串。
/// </summary>
public static string TbSettingsEnableHWA {
get {
return ResourceManager.GetString("TbSettingsEnableHWA", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Exception 的本地化字符串。 /// 查找类似 Exception 的本地化字符串。
/// </summary> /// </summary>
@@ -2509,6 +2473,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 FontSize 的本地化字符串。
/// </summary>
public static string TbSettingsFontSize {
get {
return ResourceManager.GetString("TbSettingsFontSize", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Http Port 的本地化字符串。 /// 查找类似 Http Port 的本地化字符串。
/// </summary> /// </summary>
@@ -2527,15 +2500,6 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Enable IPv6 的本地化字符串。
/// </summary>
public static string TbSettingsIpv6 {
get {
return ResourceManager.GetString("TbSettingsIpv6", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Keep older when deduplication 的本地化字符串。 /// 查找类似 Keep older when deduplication 的本地化字符串。
/// </summary> /// </summary>
@@ -2546,7 +2510,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Language 的本地化字符串。 /// 查找类似 Language(Restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLanguage { public static string TbSettingsLanguage {
get { get {
@@ -2555,7 +2519,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Record local logs 的本地化字符串。 /// 查找类似 Enable Log 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLogEnabled { public static string TbSettingsLogEnabled {
get { get {
@@ -2563,6 +2527,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Enable logging to file 的本地化字符串。
/// </summary>
public static string TbSettingsLogEnabledToFile {
get {
return ResourceManager.GetString("TbSettingsLogEnabledToFile", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Log Level 的本地化字符串。 /// 查找类似 Log Level 的本地化字符串。
/// </summary> /// </summary>
@@ -2599,15 +2572,6 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Pac listen port 的本地化字符串。
/// </summary>
public static string TbSettingsPacListenPort {
get {
return ResourceManager.GetString("TbSettingsPacListenPort", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Auth pass 的本地化字符串。 /// 查找类似 Auth pass 的本地化字符串。
/// </summary> /// </summary>
@@ -2635,15 +2599,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> /// <summary>
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。 /// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
/// </summary> /// </summary>
@@ -2680,6 +2635,24 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
/// </summary>
public static string TbSettingsSpeedTestTimeout {
get {
return ResourceManager.GetString("TbSettingsSpeedTestTimeout", resourceCulture);
}
}
/// <summary>
/// 查找类似 SpeedTest Url 的本地化字符串。
/// </summary>
public static string TbSettingsSpeedTestUrl {
get {
return ResourceManager.GetString("TbSettingsSpeedTestUrl", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Start on boot 的本地化字符串。 /// 查找类似 Start on boot 的本地化字符串。
/// </summary> /// </summary>
@@ -2761,6 +2734,24 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 Bypass Mode 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeBypassMode {
get {
return ResourceManager.GetString("TbSettingsTunModeBypassMode", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable: If no route matches, the final proxy 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeBypassModeTip {
get {
return ResourceManager.GetString("TbSettingsTunModeBypassModeTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Custom Template 的本地化字符串。 /// 查找类似 Custom Template 的本地化字符串。
/// </summary> /// </summary>
@@ -2788,6 +2779,33 @@ 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>
public static string TbSettingsTunModeProxyIP {
get {
return ResourceManager.GetString("TbSettingsTunModeProxyIP", resourceCulture);
}
}
/// <summary>
/// 查找类似 Proxy Process name, separated by commas (,) 的本地化字符串。
/// </summary>
public static string TbSettingsTunModeProxyProcess {
get {
return ResourceManager.GetString("TbSettingsTunModeProxyProcess", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Show console 的本地化字符串。 /// 查找类似 Show console 的本地化字符串。
/// </summary> /// </summary>
@@ -2815,6 +2833,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 ShortId 的本地化字符串。
/// </summary>
public static string TbShortId {
get {
return ResourceManager.GetString("TbShortId", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 SNI 的本地化字符串。 /// 查找类似 SNI 的本地化字符串。
/// </summary> /// </summary>
@@ -2824,6 +2851,15 @@ namespace v2rayN.Resx {
} }
} }
/// <summary>
/// 查找类似 SpiderX 的本地化字符串。
/// </summary>
public static string TbSpiderX {
get {
return ResourceManager.GetString("TbSpiderX", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 TLS 的本地化字符串。 /// 查找类似 TLS 的本地化字符串。
/// </summary> /// </summary>
@@ -2869,6 +2905,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> /// <summary>
/// 查找类似 *Default value tcp 的本地化字符串。 /// 查找类似 *Default value tcp 的本地化字符串。
/// </summary> /// </summary>
@@ -3005,7 +3050,7 @@ namespace v2rayN.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *QUIC securty 的本地化字符串。 /// 查找类似 *QUIC security 的本地化字符串。
/// </summary> /// </summary>
public static string TransportRequestHostTip4 { public static string TransportRequestHostTip4 {
get { get {

View File

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

View File

@@ -195,9 +195,6 @@
<data name="LvAddress" xml:space="preserve"> <data name="LvAddress" xml:space="preserve">
<value>Address</value> <value>Address</value>
</data> </data>
<data name="LvAlias" xml:space="preserve">
<value>Alias</value>
</data>
<data name="LvEncryptionMethod" xml:space="preserve"> <data name="LvEncryptionMethod" xml:space="preserve">
<value>Security</value> <value>Security</value>
</data> </data>
@@ -210,9 +207,6 @@
<data name="LvSubscription" xml:space="preserve"> <data name="LvSubscription" xml:space="preserve">
<value>Subs group</value> <value>Subs group</value>
</data> </data>
<data name="LvTestResults" xml:space="preserve">
<value>Test Results</value>
</data>
<data name="LvTodayDownloadDataAmount" xml:space="preserve"> <data name="LvTodayDownloadDataAmount" xml:space="preserve">
<value>Download traffic today</value> <value>Download traffic today</value>
</data> </data>
@@ -228,9 +222,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>Transport</value> <value>Transport</value>
</data> </data>
<data name="MediumFresh" xml:space="preserve">
<value>Medium</value>
</data>
<data name="MsgClearSubscription" xml:space="preserve"> <data name="MsgClearSubscription" xml:space="preserve">
<value>Clear original subscription content</value> <value>Clear original subscription content</value>
</data> </data>
@@ -246,27 +237,15 @@
<data name="MsgNoValidSubscription" xml:space="preserve"> <data name="MsgNoValidSubscription" xml:space="preserve">
<value>No valid subscriptions set</value> <value>No valid subscriptions set</value>
</data> </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"> <data name="MsgParsingSuccessfully" xml:space="preserve">
<value>Resolve {0} successfully</value> <value>Resolve {0} successfully</value>
</data> </data>
<data name="MsgSimplifyPAC" xml:space="preserve">
<value>Simplify PAC Success</value>
</data>
<data name="MsgStartGettingSubscriptions" xml:space="preserve"> <data name="MsgStartGettingSubscriptions" xml:space="preserve">
<value>Start getting subscriptions</value> <value>Start getting subscriptions</value>
</data> </data>
<data name="MsgStartUpdating" xml:space="preserve"> <data name="MsgStartUpdating" xml:space="preserve">
<value>Start updating {0}...</value> <value>Start updating {0}...</value>
</data> </data>
<data name="MsgStartUpdatingPAC" xml:space="preserve">
<value>Start updating PAC...</value>
</data>
<data name="MsgSubscriptionDecodingFailed" xml:space="preserve"> <data name="MsgSubscriptionDecodingFailed" xml:space="preserve">
<value>Invalid subscription content</value> <value>Invalid subscription content</value>
</data> </data>
@@ -285,9 +264,6 @@
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve"> <data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
<value>Update Core successfully! Restarting service...</value> <value>Update Core successfully! Restarting service...</value>
</data> </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"> <data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Non-VMess or ss protocol</value> <value>Non-VMess or ss protocol</value>
</data> </data>
@@ -315,9 +291,6 @@
<data name="PleaseSelectServer" xml:space="preserve"> <data name="PleaseSelectServer" xml:space="preserve">
<value>Please select the server first</value> <value>Please select the server first</value>
</data> </data>
<data name="QuickFresh" xml:space="preserve">
<value>Fast</value>
</data>
<data name="RemoveDuplicateServerResult" xml:space="preserve"> <data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>Servers deduplication completed. Old: {0}, New: {1}.</value> <value>Servers deduplication completed. Old: {0}, New: {1}.</value>
</data> </data>
@@ -330,15 +303,6 @@
<data name="SaveServerConfigurationIn" xml:space="preserve"> <data name="SaveServerConfigurationIn" xml:space="preserve">
<value>The server configuration file is saved at: {0}</value> <value>The server configuration file is saved at: {0}</value>
</data> </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"> <data name="StartService" xml:space="preserve">
<value>Start service ({0})...</value> <value>Start service ({0})...</value>
</data> </data>
@@ -380,7 +344,7 @@
<value>Count</value> <value>Count</value>
</data> </data>
<data name="MsgNeedUrl" xml:space="preserve"> <data name="MsgNeedUrl" xml:space="preserve">
<value>Please fill in the address (Url)</value> <value>Please fill in the Url</value>
</data> </data>
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve"> <data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value> <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> <value>*h2 host Separated by commas (,)</value>
</data> </data>
<data name="TransportRequestHostTip4" xml:space="preserve"> <data name="TransportRequestHostTip4" xml:space="preserve">
<value>*QUIC securty</value> <value>*QUIC security</value>
</data> </data>
<data name="TransportHeaderTypeTip1" xml:space="preserve"> <data name="TransportHeaderTypeTip1" xml:space="preserve">
<value>*tcp camouflage type</value> <value>*tcp camouflage type</value>
@@ -449,7 +413,7 @@
<value>Ungrouped</value> <value>Ungrouped</value>
</data> </data>
<data name="AllGroupServers" xml:space="preserve"> <data name="AllGroupServers" xml:space="preserve">
<value>All servers</value> <value>All</value>
</data> </data>
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>Please browse to import server configuration</value> <value>Please browse to import server configuration</value>
@@ -470,10 +434,7 @@
<value>Local</value> <value>Local</value>
</data> </data>
<data name="MsgServerTitle" xml:space="preserve"> <data name="MsgServerTitle" xml:space="preserve">
<value>Servers Filter</value> <value>Servers Filter, press Enter to execute</value>
</data>
<data name="NetFrameworkRequirementsTip" xml:space="preserve">
<value>Normal use of this version requires .NET Framework 4.8</value>
</data> </data>
<data name="menuCheckUpdate" xml:space="preserve"> <data name="menuCheckUpdate" xml:space="preserve">
<value>Check Update</value> <value>Check Update</value>
@@ -506,7 +467,7 @@
<value>Servers</value> <value>Servers</value>
</data> </data>
<data name="menuSetting" xml:space="preserve"> <data name="menuSetting" xml:space="preserve">
<value>Setting</value> <value>Settings</value>
</data> </data>
<data name="menuSubGroupUpdate" xml:space="preserve"> <data name="menuSubGroupUpdate" xml:space="preserve">
<value>Update current subscription without proxy</value> <value>Update current subscription without proxy</value>
@@ -518,7 +479,7 @@
<value>Subscription group</value> <value>Subscription group</value>
</data> </data>
<data name="menuSubSetting" xml:space="preserve"> <data name="menuSubSetting" xml:space="preserve">
<value>Subscription group Setting</value> <value>Subscription group Settings</value>
</data> </data>
<data name="menuSubUpdate" xml:space="preserve"> <data name="menuSubUpdate" xml:space="preserve">
<value>Update subscription without proxy</value> <value>Update subscription without proxy</value>
@@ -548,7 +509,7 @@
<value>Dark Mode</value> <value>Dark Mode</value>
</data> </data>
<data name="TbSettingsLanguage" xml:space="preserve"> <data name="TbSettingsLanguage" xml:space="preserve">
<value>Language</value> <value>Language(Restart)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>Import bulk URL from clipboard (Ctrl+V)</value> <value>Import bulk URL from clipboard (Ctrl+V)</value>
@@ -763,12 +724,6 @@
<data name="TbSettingsAutoHideStartup" xml:space="preserve"> <data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>Auto hide startup</value> <value>Auto hide startup</value>
</data> </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"> <data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval of and Geo (hours)</value> <value>Automatic update interval of and Geo (hours)</value>
</data> </data>
@@ -808,14 +763,11 @@
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve"> <data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>Ignore Geo files when updating core</value> <value>Ignore Geo files when updating core</value>
</data> </data>
<data name="TbSettingsIpv6" xml:space="preserve">
<value>Enable IPv6</value>
</data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve"> <data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>Keep older when deduplication</value> <value>Keep older when deduplication</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>Record local logs</value> <value>Enable Log</value>
</data> </data>
<data name="TbSettingsLogLevel" xml:space="preserve"> <data name="TbSettingsLogLevel" xml:space="preserve">
<value>Log Level</value> <value>Log Level</value>
@@ -826,18 +778,12 @@
<data name="TbSettingsN" xml:space="preserve"> <data name="TbSettingsN" xml:space="preserve">
<value>v2rayN settings</value> <value>v2rayN settings</value>
</data> </data>
<data name="TbSettingsPacListenPort" xml:space="preserve">
<value>Pac listen port</value>
</data>
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>Auth pass</value> <value>Auth pass</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve"> <data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>Custom DNS (multiple, separated by commas (,))</value> <value>Custom DNS (multiple, separated by commas (,))</value>
</data> </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"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>Set Win10 UWP Loopback</value> <value>Set Win10 UWP Loopback</value>
</data> </data>
@@ -881,7 +827,7 @@
<value>Display GUI</value> <value>Display GUI</value>
</data> </data>
<data name="TbGlobalHotkeySetting" xml:space="preserve"> <data name="TbGlobalHotkeySetting" xml:space="preserve">
<value>GlobalHotkey Setting</value> <value>GlobalHotkey Settings</value>
</data> </data>
<data name="TbGlobalHotkeySettingTip" xml:space="preserve"> <data name="TbGlobalHotkeySettingTip" xml:space="preserve">
<value>Set directly by pressing the keyboard, Take effect after restart</value> <value>Set directly by pressing the keyboard, Take effect after restart</value>
@@ -983,7 +929,7 @@
<value>Import Rules From Sub Url</value> <value>Import Rules From Sub Url</value>
</data> </data>
<data name="menuRoutingRuleSetting" xml:space="preserve"> <data name="menuRoutingRuleSetting" xml:space="preserve">
<value>Rule Setting</value> <value>Rule Settings</value>
</data> </data>
<data name="menuRuleAdd" xml:space="preserve"> <data name="menuRuleAdd" xml:space="preserve">
<value>Rule Add</value> <value>Rule Add</value>
@@ -1022,7 +968,7 @@
<value>RouteOnly</value> <value>RouteOnly</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>One-click test Latency and speed (Ctrl+E)</value> <value>One-click multi test Latency and speed (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>Delay(ms)</value> <value>Delay(ms)</value>
@@ -1097,7 +1043,7 @@
<value>FontFamily(Require restart)</value> <value>FontFamily(Require restart)</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>Copy the font TTF file to the directory Resources\Fonts, restart the settings</value> <value>Copy the font TTF file to the directory guiFonts, restart the settings</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve"> <data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http port=socks port+1</value> <value>http port=socks port+1</value>
@@ -1105,4 +1051,73 @@
<data name="TbSettingsStartBootTip" xml:space="preserve"> <data name="TbSettingsStartBootTip" xml:space="preserve">
<value>Set this with admin privileges, get admin privileges after startup</value> <value>Set this with admin privileges, get admin privileges after startup</value>
</data> </data>
<data name="TbSettingsFontSize" xml:space="preserve">
<value>FontSize</value>
</data>
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
<value>Proxy IP CIDR, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
<value>Proxy Process name, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
<value>Bypass Mode</value>
</data>
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
<value>Enable: If no route matches, the final proxy</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>SpeedTest Single Timeout Value</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest Url</value>
</data>
<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;Subscription conversion will be invalid</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>
<data name="LvConvertTarget" xml:space="preserve">
<value>Convert target type</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>Please leave blank if no conversion is required</value>
</data>
</root> </root>

File diff suppressed because it is too large Load Diff

View File

@@ -130,7 +130,7 @@
<value>配置格式不正确</value> <value>配置格式不正确</value>
</data> </data>
<data name="CustomServerTips" xml:space="preserve"> <data name="CustomServerTips" xml:space="preserve">
<value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value> <value>注意,自定义配置完全依赖您自己的配置,不能使用所有设置功能。如需使用系统代理请手修改监听端口。</value>
</data> </data>
<data name="Downloading" xml:space="preserve"> <data name="Downloading" xml:space="preserve">
<value>下载开始...</value> <value>下载开始...</value>
@@ -148,7 +148,7 @@
<value>生成默认配置文件失败</value> <value>生成默认配置文件失败</value>
</data> </data>
<data name="FailedGetDefaultConfiguration" xml:space="preserve"> <data name="FailedGetDefaultConfiguration" xml:space="preserve">
<value>取默认配置失败</value> <value>取默认配置失败</value>
</data> </data>
<data name="FailedImportedCustomServer" xml:space="preserve"> <data name="FailedImportedCustomServer" xml:space="preserve">
<value>导入自定义配置服务器失败</value> <value>导入自定义配置服务器失败</value>
@@ -195,9 +195,6 @@
<data name="LvAddress" xml:space="preserve"> <data name="LvAddress" xml:space="preserve">
<value>地址</value> <value>地址</value>
</data> </data>
<data name="LvAlias" xml:space="preserve">
<value>别名</value>
</data>
<data name="LvEncryptionMethod" xml:space="preserve"> <data name="LvEncryptionMethod" xml:space="preserve">
<value>加密方式</value> <value>加密方式</value>
</data> </data>
@@ -210,9 +207,6 @@
<data name="LvSubscription" xml:space="preserve"> <data name="LvSubscription" xml:space="preserve">
<value>订阅分组</value> <value>订阅分组</value>
</data> </data>
<data name="LvTestResults" xml:space="preserve">
<value>测试结果</value>
</data>
<data name="LvTodayDownloadDataAmount" xml:space="preserve"> <data name="LvTodayDownloadDataAmount" xml:space="preserve">
<value>今日下载</value> <value>今日下载</value>
</data> </data>
@@ -228,9 +222,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>传输协议</value> <value>传输协议</value>
</data> </data>
<data name="MediumFresh" xml:space="preserve">
<value>中等</value>
</data>
<data name="MsgClearSubscription" xml:space="preserve"> <data name="MsgClearSubscription" xml:space="preserve">
<value>清除原订阅内容</value> <value>清除原订阅内容</value>
</data> </data>
@@ -246,27 +237,15 @@
<data name="MsgNoValidSubscription" xml:space="preserve"> <data name="MsgNoValidSubscription" xml:space="preserve">
<value>未设置有效的订阅</value> <value>未设置有效的订阅</value>
</data> </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"> <data name="MsgParsingSuccessfully" xml:space="preserve">
<value>解析{0}成功</value> <value>解析{0}成功</value>
</data> </data>
<data name="MsgSimplifyPAC" xml:space="preserve">
<value>简化PAC成功</value>
</data>
<data name="MsgStartGettingSubscriptions" xml:space="preserve"> <data name="MsgStartGettingSubscriptions" xml:space="preserve">
<value>开始获取订阅内容</value> <value>开始获取订阅内容</value>
</data> </data>
<data name="MsgStartUpdating" xml:space="preserve"> <data name="MsgStartUpdating" xml:space="preserve">
<value>开始更新 {0}...</value> <value>开始更新 {0}...</value>
</data> </data>
<data name="MsgStartUpdatingPAC" xml:space="preserve">
<value>开始更新 PAC...</value>
</data>
<data name="MsgSubscriptionDecodingFailed" xml:space="preserve"> <data name="MsgSubscriptionDecodingFailed" xml:space="preserve">
<value>无效的订阅内容</value> <value>无效的订阅内容</value>
</data> </data>
@@ -285,9 +264,6 @@
<data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve"> <data name="MsgUpdateV2rayCoreSuccessfullyMore" xml:space="preserve">
<value>更新Core成功正在重启服务...</value> <value>更新Core成功正在重启服务...</value>
</data> </data>
<data name="NeedHttpGlobalProxy" xml:space="preserve">
<value>此功能依赖Http全局代理,请先设置正确。</value>
</data>
<data name="NonvmessOrssProtocol" xml:space="preserve"> <data name="NonvmessOrssProtocol" xml:space="preserve">
<value>非VMess或ss协议</value> <value>非VMess或ss协议</value>
</data> </data>
@@ -304,7 +280,7 @@
<value>操作失败,请检查重试</value> <value>操作失败,请检查重试</value>
</data> </data>
<data name="PleaseFillRemarks" xml:space="preserve"> <data name="PleaseFillRemarks" xml:space="preserve">
<value>请填写备注</value> <value>请填写别名</value>
</data> </data>
<data name="PleaseSelectEncryption" xml:space="preserve"> <data name="PleaseSelectEncryption" xml:space="preserve">
<value>请选择加密方式</value> <value>请选择加密方式</value>
@@ -315,9 +291,6 @@
<data name="PleaseSelectServer" xml:space="preserve"> <data name="PleaseSelectServer" xml:space="preserve">
<value>请先选择服务器</value> <value>请先选择服务器</value>
</data> </data>
<data name="QuickFresh" xml:space="preserve">
<value>快</value>
</data>
<data name="RemoveDuplicateServerResult" xml:space="preserve"> <data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>服务器去重完成。原数量: {0},现数量: {1}</value> <value>服务器去重完成。原数量: {0},现数量: {1}</value>
</data> </data>
@@ -330,15 +303,6 @@
<data name="SaveServerConfigurationIn" xml:space="preserve"> <data name="SaveServerConfigurationIn" xml:space="preserve">
<value>服务端配置文件保存在:{0}</value> <value>服务端配置文件保存在:{0}</value>
</data> </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"> <data name="StartService" xml:space="preserve">
<value>启动服务({0})...</value> <value>启动服务({0})...</value>
</data> </data>
@@ -380,7 +344,7 @@
<value>数量</value> <value>数量</value>
</data> </data>
<data name="MsgNeedUrl" xml:space="preserve"> <data name="MsgNeedUrl" xml:space="preserve">
<value>请填写地址(Url)</value> <value>请填写Url</value>
</data> </data>
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve"> <data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
<value>是否追加规则?选择是则追加,选择否则替换</value> <value>是否追加规则?选择是则追加,选择否则替换</value>
@@ -410,13 +374,13 @@
<value>*grpc serviceName</value> <value>*grpc serviceName</value>
</data> </data>
<data name="TransportRequestHostTip1" xml:space="preserve"> <data name="TransportRequestHostTip1" xml:space="preserve">
<value>*http host中间逗号(,)隔</value> <value>*http host中间逗号(,)隔</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws host</value> <value>*ws host</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中间逗号(,)隔</value> <value>*h2 host中间逗号(,)隔</value>
</data> </data>
<data name="TransportRequestHostTip4" xml:space="preserve"> <data name="TransportRequestHostTip4" xml:space="preserve">
<value>*QUIC 加密方式</value> <value>*QUIC 加密方式</value>
@@ -449,7 +413,7 @@
<value>未分组服务器</value> <value>未分组服务器</value>
</data> </data>
<data name="AllGroupServers" xml:space="preserve"> <data name="AllGroupServers" xml:space="preserve">
<value>所有服务器</value> <value>所有</value>
</data> </data>
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>请浏览导入服务器配置</value> <value>请浏览导入服务器配置</value>
@@ -470,10 +434,7 @@
<value>本地</value> <value>本地</value>
</data> </data>
<data name="MsgServerTitle" xml:space="preserve"> <data name="MsgServerTitle" xml:space="preserve">
<value>服务器过滤器</value> <value>服务器过滤器,按回车执行</value>
</data>
<data name="NetFrameworkRequirementsTip" xml:space="preserve">
<value>正常使用此版本需要.NET Framework 4.8,请更新后重启</value>
</data> </data>
<data name="menuCheckUpdate" xml:space="preserve"> <data name="menuCheckUpdate" xml:space="preserve">
<value>检查更新</value> <value>检查更新</value>
@@ -548,7 +509,7 @@
<value>暗黑模式</value> <value>暗黑模式</value>
</data> </data>
<data name="TbSettingsLanguage" xml:space="preserve"> <data name="TbSettingsLanguage" xml:space="preserve">
<value>语言</value> <value>语言(重启)</value>
</data> </data>
<data name="menuAddServerViaClipboard" xml:space="preserve"> <data name="menuAddServerViaClipboard" xml:space="preserve">
<value>从剪贴板导入批量URL (Ctrl+V)</value> <value>从剪贴板导入批量URL (Ctrl+V)</value>
@@ -710,7 +671,7 @@
<value>SNI</value> <value>SNI</value>
</data> </data>
<data name="TbStreamSecurity" xml:space="preserve"> <data name="TbStreamSecurity" xml:space="preserve">
<value>TLS</value> <value>传输层安全(TLS)</value>
</data> </data>
<data name="TipNetwork" xml:space="preserve"> <data name="TipNetwork" xml:space="preserve">
<value>*默认tcp,选错会无法连接</value> <value>*默认tcp,选错会无法连接</value>
@@ -763,12 +724,6 @@
<data name="TbSettingsAutoHideStartup" xml:space="preserve"> <data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>启动后隐藏窗口</value> <value>启动后隐藏窗口</value>
</data> </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"> <data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>自动更新Geo文件的间隔(单位小时)</value> <value>自动更新Geo文件的间隔(单位小时)</value>
</data> </data>
@@ -808,14 +763,11 @@
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve"> <data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core时忽略Geo文件</value> <value>更新Core时忽略Geo文件</value>
</data> </data>
<data name="TbSettingsIpv6" xml:space="preserve">
<value>启用IPv6</value>
</data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve"> <data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>去重时保留序号较小的项</value> <value>去重时保留序号较小的项</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>记录本地日志(默认关闭)</value> <value>启用日志</value>
</data> </data>
<data name="TbSettingsLogLevel" xml:space="preserve"> <data name="TbSettingsLogLevel" xml:space="preserve">
<value>日志等级</value> <value>日志等级</value>
@@ -826,17 +778,11 @@
<data name="TbSettingsN" xml:space="preserve"> <data name="TbSettingsN" xml:space="preserve">
<value>v2rayN 设置</value> <value>v2rayN 设置</value>
</data> </data>
<data name="TbSettingsPacListenPort" xml:space="preserve">
<value>Pac监听端口号</value>
</data>
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>认证密码</value> <value>认证密码</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve"> <data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>自定义DNS(可多个,用逗号(,)隔)</value> <value>自定义DNS(可多个,用逗号(,)隔)</value>
</data>
<data name="TbSettingsSaveTip" xml:space="preserve">
<value>修改以下参数后,点击保存才生效</value>
</data> </data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>解除Win10 UWP应用回环代理限制</value> <value>解除Win10 UWP应用回环代理限制</value>
@@ -905,7 +851,7 @@
<value>路由</value> <value>路由</value>
</data> </data>
<data name="NotRunAsAdmin" xml:space="preserve"> <data name="NotRunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value> <value>以管理员身份运行</value>
</data> </data>
<data name="RunAsAdmin" xml:space="preserve"> <data name="RunAsAdmin" xml:space="preserve">
<value>以管理员身份运行</value> <value>以管理员身份运行</value>
@@ -1022,7 +968,7 @@
<value>RouteOnly</value> <value>RouteOnly</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>一键测试延迟和速度 (Ctrl+E)</value> <value>一键多线程测试延迟和速度 (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>延迟(ms)</value> <value>延迟(ms)</value>
@@ -1097,7 +1043,7 @@
<value>当前字体(需重启)</value> <value>当前字体(需重启)</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>拷贝字体TTF文件到目录Resources\Fonts重启设置</value> <value>拷贝字体TTF文件到目录guiFonts重启设置</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve"> <data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口=socks端口+1</value> <value>http端口=socks端口+1</value>
@@ -1105,4 +1051,70 @@
<data name="TbSettingsStartBootTip" xml:space="preserve"> <data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理员权限设置此项,在启动后获得管理员权限</value> <value>以管理员权限设置此项,在启动后获得管理员权限</value>
</data> </data>
<data name="TbSettingsFontSize" xml:space="preserve">
<value>字体大小</value>
</data>
<data name="TbSettingsTunModeProxyIP" xml:space="preserve">
<value>代理的IP CIDR用逗号(,)分隔</value>
</data>
<data name="TbSettingsTunModeProxyProcess" xml:space="preserve">
<value>代理的进程名,用逗号(,)分隔</value>
</data>
<data name="TbSettingsTunModeBypassMode" xml:space="preserve">
<value>绕行模式</value>
</data>
<data name="TbSettingsTunModeBypassModeTip" xml:space="preserve">
<value>启用:路由无匹配则最终代理</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>测速单个超时值</value>
</data>
<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>
<data name="LvConvertTarget" xml:space="preserve">
<value>订阅转换目标类型</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>不需要转换时请留空</value>
</data>
</root> </root>

View File

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

View File

@@ -1,28 +1,15 @@
{ {
"dns": { "log": {
"servers": [ "disabled": $log_disabled$,
{ "level": "debug",
"tag": "local", $log_output$
"address": "223.5.5.5", "timestamp": true
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
}
],
"rules": [
{
"geosite": "category-ads-all",
"server": "block",
"disable_cache": true
}
],
"strategy": "ipv4_only"
}, },
"dns": $dns_object$ ,
"inbounds": [ "inbounds": [
{ {
"type": "tun", "type": "tun",
"tag": "tun-in",
"interface_name": "singbox_tun", "interface_name": "singbox_tun",
"inet4_address": "172.19.0.1/30", "inet4_address": "172.19.0.1/30",
@@ -102,6 +89,9 @@
} }
$ruleDirectIPs$ $ruleDirectIPs$
$ruleDirectProcess$ $ruleDirectProcess$
$ruleProxyIPs$
$ruleProxyProcess$
$ruleFinally$
] ]
} }
} }

View File

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

View File

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

View File

@@ -1,13 +1,13 @@
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace v2rayN namespace v2rayN
{ {
/* /*
* See: * See:
* http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net * http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net
*/ */
public class Job : IDisposable public class Job : IDisposable
{ {
private IntPtr handle = IntPtr.Zero; private IntPtr handle = IntPtr.Zero;
@@ -16,12 +16,12 @@ namespace v2rayN
{ {
handle = CreateJobObject(IntPtr.Zero, null); handle = CreateJobObject(IntPtr.Zero, null);
IntPtr extendedInfoPtr = IntPtr.Zero; IntPtr extendedInfoPtr = IntPtr.Zero;
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
{ {
LimitFlags = 0x2000 LimitFlags = 0x2000
}; };
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
{ {
BasicLimitInformation = info BasicLimitInformation = info
}; };
@@ -95,12 +95,12 @@ namespace v2rayN
Dispose(false); Dispose(false);
} }
#endregion #endregion IDisposable
#region Interop #region Interop
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr CreateJobObject(IntPtr a, string lpName); private static extern IntPtr CreateJobObject(IntPtr a, string? lpName);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
@@ -112,13 +112,13 @@ namespace v2rayN
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject); private static extern bool CloseHandle(IntPtr hObject);
#endregion #endregion Interop
} }
#region Helper classes #region Helper classes
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS internal struct IO_COUNTERS
{ {
public UInt64 ReadOperationCount; public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount; public UInt64 WriteOperationCount;
@@ -128,9 +128,8 @@ namespace v2rayN
public UInt64 OtherTransferCount; public UInt64 OtherTransferCount;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{ {
public Int64 PerProcessUserTimeLimit; public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit; public Int64 PerJobUserTimeLimit;
@@ -152,7 +151,7 @@ namespace v2rayN
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{ {
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo; public IO_COUNTERS IoInfo;
@@ -173,5 +172,5 @@ namespace v2rayN
GroupInformation = 11 GroupInformation = 11
} }
#endregion #endregion Helper classes
} }

View File

@@ -9,8 +9,8 @@ namespace v2rayN.Tool
{ {
public static void Setup() public static void Setup()
{ {
LoggingConfiguration config = new LoggingConfiguration(); LoggingConfiguration config = new();
FileTarget fileTarget = new FileTarget(); FileTarget fileTarget = new();
config.AddTarget("file", fileTarget); config.AddTarget("file", fileTarget);
fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}"; fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}";
fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt"); fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt");
@@ -18,6 +18,14 @@ namespace v2rayN.Tool
LogManager.Configuration = config; LogManager.Configuration = config;
} }
public static void LoggingEnabled(bool enable)
{
if (!enable)
{
LogManager.SuspendLogging();
}
}
public static void ClearLogs() public static void ClearLogs()
{ {
Task.Run(() => Task.Run(() =>
@@ -44,4 +52,4 @@ namespace v2rayN.Tool
}); });
} }
} }
} }

View File

@@ -9,12 +9,13 @@ namespace v2rayN.Tool
{ {
return _OrderBy<T>(query, propertyName, false); return _OrderBy<T>(query, propertyName, false);
} }
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName) public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName)
{ {
return _OrderBy<T>(query, propertyName, true); return _OrderBy<T>(query, propertyName, true);
} }
static IOrderedQueryable<T> _OrderBy<T>(IQueryable<T> query, string propertyName, bool isDesc) private static IOrderedQueryable<T> _OrderBy<T>(IQueryable<T> query, string propertyName, bool isDesc)
{ {
string methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal"; string methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal";
@@ -25,15 +26,18 @@ namespace v2rayN.Tool
return (IOrderedQueryable<T>)method.Invoke(null, new object[] { query, memberProp }); return (IOrderedQueryable<T>)method.Invoke(null, new object[] { query, memberProp });
} }
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty) public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
{//public {//public
return query.OrderBy(_GetLamba<T, TProp>(memberProperty)); return query.OrderBy(_GetLamba<T, TProp>(memberProperty));
} }
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty) public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
{//public {//public
return query.OrderByDescending(_GetLamba<T, TProp>(memberProperty)); return query.OrderByDescending(_GetLamba<T, TProp>(memberProperty));
} }
static Expression<Func<T, TProp>> _GetLamba<T, TProp>(PropertyInfo memberProperty)
private static Expression<Func<T, TProp>> _GetLamba<T, TProp>(PropertyInfo memberProperty)
{ {
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception(); if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
@@ -43,4 +47,4 @@ namespace v2rayN.Tool
return lamba; return lamba;
} }
} }
} }

View File

@@ -1,45 +1,24 @@
using System.Windows.Forms; using System.Windows;
namespace v2rayN namespace v2rayN
{ {
class UI internal class UI
{ {
private static readonly string caption = "v2rayN";
public static void Show(string msg) 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) 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;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Web; using System.Web;
using System.Windows.Forms; using System.Windows;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
@@ -31,9 +31,8 @@ using ZXing.Windows.Compatibility;
namespace v2rayN namespace v2rayN
{ {
class Utils internal class Utils
{ {
#region Json操作 #region Json操作
/// <summary> /// <summary>
@@ -48,11 +47,10 @@ namespace v2rayN
try try
{ {
Assembly assembly = Assembly.GetExecutingAssembly(); Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(res)) using Stream? stream = assembly.GetManifestResourceStream(res);
using (StreamReader reader = new StreamReader(stream)) ArgumentNullException.ThrowIfNull(stream);
{ using StreamReader reader = new(stream);
result = reader.ReadToEnd(); result = reader.ReadToEnd();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -61,27 +59,22 @@ namespace v2rayN
return result; return result;
} }
/// <summary> /// <summary>
/// 取得存储资源 /// 取得存储资源
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string LoadResource(string res) public static string? LoadResource(string res)
{ {
string result = string.Empty;
try try
{ {
using (StreamReader reader = new StreamReader(res)) if (!File.Exists(res)) return null;
{ return File.ReadAllText(res);
result = reader.ReadToEnd();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); SaveLog(ex.Message, ex);
} }
return result; return null;
} }
/// <summary> /// <summary>
@@ -90,7 +83,7 @@ namespace v2rayN
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="strJson"></param> /// <param name="strJson"></param>
/// <returns></returns> /// <returns></returns>
public static T FromJson<T>(string strJson) public static T? FromJson<T>(string? strJson)
{ {
try try
{ {
@@ -98,8 +91,7 @@ namespace v2rayN
{ {
return default; return default;
} }
T obj = JsonConvert.DeserializeObject<T>(strJson); return JsonConvert.DeserializeObject<T>(strJson);
return obj;
} }
catch catch
{ {
@@ -112,11 +104,15 @@ namespace v2rayN
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <returns></returns>
public static string ToJson(Object obj, bool indented = true) public static string ToJson(object? obj, bool indented = true)
{ {
string result = string.Empty; string result = string.Empty;
try try
{ {
if (obj == null)
{
return result;
}
if (indented) if (indented)
{ {
result = JsonConvert.SerializeObject(obj, result = JsonConvert.SerializeObject(obj,
@@ -141,25 +137,23 @@ namespace v2rayN
/// <param name="obj"></param> /// <param name="obj"></param>
/// <param name="filePath"></param> /// <param name="filePath"></param>
/// <returns></returns> /// <returns></returns>
public static int ToJsonFile(Object obj, string filePath, bool nullValue = true) public static int ToJsonFile(object? obj, string filePath, bool nullValue = true)
{ {
int result; int result;
try try
{ {
using (StreamWriter file = File.CreateText(filePath)) using StreamWriter file = File.CreateText(filePath);
JsonSerializer serializer;
if (nullValue)
{ {
JsonSerializer serializer; serializer = new JsonSerializer() { Formatting = Formatting.Indented };
if (nullValue)
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented };
}
else
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
}
serializer.Serialize(file, obj);
} }
else
{
serializer = new JsonSerializer() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore };
}
serializer.Serialize(file, obj);
result = 0; result = 0;
} }
catch (Exception ex) catch (Exception ex)
@@ -170,12 +164,11 @@ namespace v2rayN
return result; return result;
} }
public static JObject ParseJson(string strJson) public static JObject? ParseJson(string strJson)
{ {
try try
{ {
JObject obj = JObject.Parse(strJson); return JObject.Parse(strJson);
return obj;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -183,7 +176,8 @@ namespace v2rayN
return null; return null;
} }
} }
#endregion
#endregion Json操作
#region #region
@@ -202,11 +196,11 @@ namespace v2rayN
} }
if (wrap) if (wrap)
{ {
return string.Join("," + Environment.NewLine, lst.ToArray()); return string.Join("," + Environment.NewLine, lst);
} }
else else
{ {
return string.Join(",", lst.ToArray()); return string.Join(",", lst);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -215,6 +209,7 @@ namespace v2rayN
return string.Empty; return string.Empty;
} }
} }
/// <summary> /// <summary>
/// 逗号分隔的字符串,转List<string> /// 逗号分隔的字符串,转List<string>
/// </summary> /// </summary>
@@ -225,7 +220,7 @@ namespace v2rayN
try try
{ {
str = str.Replace(Environment.NewLine, ""); str = str.Replace(Environment.NewLine, "");
return new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)); return new List<string>(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -244,8 +239,9 @@ namespace v2rayN
try try
{ {
str = str.Replace(Environment.NewLine, ""); str = str.Replace(Environment.NewLine, "");
List<string> list = new List<string>(str.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)); List<string> list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
return list.OrderBy(x => x).ToList(); list.Sort();
return list;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -286,6 +282,8 @@ namespace v2rayN
.Replace(Environment.NewLine, "") .Replace(Environment.NewLine, "")
.Replace("\n", "") .Replace("\n", "")
.Replace("\r", "") .Replace("\r", "")
.Replace('_', '/')
.Replace('-', '+')
.Replace(" ", ""); .Replace(" ", "");
if (plainText.Length % 4 > 0) if (plainText.Length % 4 > 0)
@@ -316,10 +314,11 @@ namespace v2rayN
} }
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); //SaveLog(ex.Message, ex);
return 0; return 0;
} }
} }
public static bool ToBool(object obj) public static bool ToBool(object obj)
{ {
try try
@@ -328,7 +327,7 @@ namespace v2rayN
} }
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); //SaveLog(ex.Message, ex);
return false; return false;
} }
} }
@@ -337,11 +336,11 @@ namespace v2rayN
{ {
try try
{ {
return (obj == null ? string.Empty : obj.ToString()); return obj?.ToString() ?? string.Empty;
} }
catch (Exception ex) catch (Exception ex)
{ {
SaveLog(ex.Message, ex); //SaveLog(ex.Message, ex);
return string.Empty; return string.Empty;
} }
} }
@@ -369,23 +368,22 @@ namespace v2rayN
if (GBs > 0) if (GBs > 0)
{ {
// multi GB // multi GB
/*ulong TBs = GBs / factor; long TBs = GBs / factor;
if (TBs > 0) if (TBs > 0)
{ {
// 你是魔鬼吗? 用这么多流量 result = TBs + ((GBs % factor) / (factor + 0.0));
result = TBs + GBs % factor / (factor + 0.0);
unit = "TB"; unit = "TB";
return; return;
}*/ }
result = GBs + MBs % factor / (factor + 0.0); result = GBs + ((MBs % factor) / (factor + 0.0));
unit = "GB"; unit = "GB";
return; return;
} }
result = MBs + KBs % factor / (factor + 0.0); result = MBs + ((KBs % factor) / (factor + 0.0));
unit = "MB"; unit = "MB";
return; return;
} }
result = KBs + amount % factor / (factor + 0.0); result = KBs + ((amount % factor) / (factor + 0.0));
unit = "KB"; unit = "KB";
return; return;
} }
@@ -407,6 +405,7 @@ namespace v2rayN
return Uri.EscapeDataString(url); return Uri.EscapeDataString(url);
//return HttpUtility.UrlEncode(url); //return HttpUtility.UrlEncode(url);
} }
public static string UrlDecode(string url) public static string UrlDecode(string url)
{ {
return HttpUtility.UrlDecode(url); return HttpUtility.UrlDecode(url);
@@ -414,16 +413,16 @@ namespace v2rayN
public static string GetMD5(string str) public static string GetMD5(string str)
{ {
var md5 = MD5.Create();
byte[] byteOld = Encoding.UTF8.GetBytes(str); byte[] byteOld = Encoding.UTF8.GetBytes(str);
byte[] byteNew = md5.ComputeHash(byteOld); byte[] byteNew = MD5.HashData(byteOld);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new(32);
foreach (byte b in byteNew) foreach (byte b in byteNew)
{ {
sb.Append(b.ToString("x2")); sb.Append(b.ToString("x2"));
} }
return sb.ToString(); return sb.ToString();
} }
public static ImageSource IconToImageSource(Icon icon) public static ImageSource IconToImageSource(Icon icon)
{ {
return Imaging.CreateBitmapSourceFromHIcon( return Imaging.CreateBitmapSourceFromHIcon(
@@ -432,6 +431,11 @@ namespace v2rayN
BitmapSizeOptions.FromEmptyOptions()); BitmapSizeOptions.FromEmptyOptions());
} }
/// <summary>
/// idn to idc
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string GetPunycode(string url) public static string GetPunycode(string url)
{ {
if (string.IsNullOrWhiteSpace(url)) if (string.IsNullOrWhiteSpace(url))
@@ -440,7 +444,7 @@ namespace v2rayN
} }
try try
{ {
Uri uri = new Uri(url); Uri uri = new(url);
if (uri.Host == uri.IdnHost) if (uri.Host == uri.IdnHost)
{ {
return url; return url;
@@ -456,8 +460,13 @@ namespace v2rayN
} }
} }
#endregion public static bool IsBase64String(string plainText)
{
var buffer = new Span<byte>(new byte[plainText.Length]);
return Convert.TryFromBase64String(plainText, buffer, out int _);
}
#endregion
#region #region
@@ -491,7 +500,7 @@ namespace v2rayN
{ {
return true; return true;
} }
if (text.Equals("null")) if (text == "null")
{ {
return true; return true;
} }
@@ -501,7 +510,7 @@ namespace v2rayN
/// <summary> /// <summary>
/// 验证IP地址是否合法 /// 验证IP地址是否合法
/// </summary> /// </summary>
/// <param name="ip"></param> /// <param name="ip"></param>
public static bool IsIP(string ip) public static bool IsIP(string ip)
{ {
//如果为空 //如果为空
@@ -526,7 +535,6 @@ namespace v2rayN
} }
} }
//模式字符串 //模式字符串
string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"; string pattern = @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$";
@@ -537,7 +545,7 @@ namespace v2rayN
/// <summary> /// <summary>
/// 验证Domain地址是否合法 /// 验证Domain地址是否合法
/// </summary> /// </summary>
/// <param name="domain"></param> /// <param name="domain"></param>
public static bool IsDomain(string domain) public static bool IsDomain(string domain)
{ {
//如果为空 //如果为空
@@ -560,7 +568,7 @@ namespace v2rayN
/// 验证输入字符串是否与模式字符串匹配匹配返回true /// 验证输入字符串是否与模式字符串匹配匹配返回true
/// </summary> /// </summary>
/// <param name="input">输入字符串</param> /// <param name="input">输入字符串</param>
/// <param name="pattern">模式字符串</param> /// <param name="pattern">模式字符串</param>
public static bool IsMatch(string input, string pattern) public static bool IsMatch(string input, string pattern)
{ {
return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase); return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
@@ -568,27 +576,22 @@ namespace v2rayN
public static bool IsIpv6(string ip) public static bool IsIpv6(string ip)
{ {
IPAddress address; if (IPAddress.TryParse(ip, out IPAddress? address))
if (IPAddress.TryParse(ip, out address))
{ {
switch (address.AddressFamily) return address.AddressFamily switch
{ {
case AddressFamily.InterNetwork: AddressFamily.InterNetwork => false,
return false; AddressFamily.InterNetworkV6 => true,
case AddressFamily.InterNetworkV6: _ => false,
return true; };
default:
return false;
}
} }
return false; return false;
} }
#endregion #endregion
#region #region
/// <summary> /// <summary>
/// 开机自动启动 /// 开机自动启动
/// </summary> /// </summary>
@@ -642,7 +645,7 @@ namespace v2rayN
string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, ""); string value = RegReadValue(Global.AutoRunRegPath, Global.AutoRunName, "");
string exePath = GetExePath(); string exePath = GetExePath();
if (value?.Equals(exePath) == true || value?.Equals($"\"{exePath}\"") == true) if (value == exePath || value == $"\"{exePath}\"")
{ {
return true; return true;
} }
@@ -674,21 +677,21 @@ namespace v2rayN
/// <returns></returns> /// <returns></returns>
public static string GetExePath() public static string GetExePath()
{ {
return Application.ExecutablePath; return Environment.ProcessPath;
} }
public static string StartupPath() 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 try
{ {
regKey = Registry.CurrentUser.OpenSubKey(path, false); regKey = Registry.CurrentUser.OpenSubKey(path, false);
string value = regKey?.GetValue(name) as string; string? value = regKey?.GetValue(name) as string;
if (IsNullOrEmpty(value)) if (IsNullOrEmpty(value))
{ {
return def; return def;
@@ -711,7 +714,7 @@ namespace v2rayN
public static void RegWriteValue(string path, string name, object value) public static void RegWriteValue(string path, string name, object value)
{ {
RegistryKey regKey = null; RegistryKey? regKey = null;
try try
{ {
regKey = Registry.CurrentUser.CreateSubKey(path); regKey = Registry.CurrentUser.CreateSubKey(path);
@@ -743,14 +746,12 @@ namespace v2rayN
public static bool CheckForDotNetVersion(int release = 528040) public static bool CheckForDotNetVersion(int release = 528040)
{ {
const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey)) using RegistryKey? ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey);
if (ndpKey?.GetValue("Release") != null)
{ {
if (ndpKey != null && ndpKey.GetValue("Release") != null) return (int)ndpKey.GetValue("Release") >= release;
{
return (int)ndpKey.GetValue("Release") >= release ? true : false;
}
return false;
} }
return false;
} }
/// <summary> /// <summary>
@@ -771,30 +772,32 @@ namespace v2rayN
string taskDescription = description; string taskDescription = description;
string deamonFileName = fileName; string deamonFileName = fileName;
using (var taskService = new TaskService()) using var taskService = new TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
foreach (var t in tasks)
{ {
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName)); taskService.RootFolder.DeleteTask(t.Name);
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
if (string.IsNullOrEmpty(fileName))
{
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription;
task.Settings.DisallowStartIfOnBatteries = false;
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromMinutes(1) });
task.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
} }
if (string.IsNullOrEmpty(fileName))
{
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription;
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
} }
#endregion #endregion
#region #region
@@ -859,7 +862,8 @@ namespace v2rayN
} }
return inUse; return inUse;
} }
#endregion
#endregion
#region #region
@@ -900,16 +904,13 @@ namespace v2rayN
public static T DeepCopy<T>(T obj) public static T DeepCopy<T>(T obj)
{ {
object retval; object retval;
using (MemoryStream ms = new MemoryStream()) MemoryStream ms = new MemoryStream();
{ BinaryFormatter bf = new BinaryFormatter();
BinaryFormatter bf = new BinaryFormatter(); //序列化成流
//序列化成流 bf.Serialize(ms, obj);
bf.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin);
ms.Seek(0, SeekOrigin.Begin); //反序列化成对象
//反序列化成对象 retval = bf.Deserialize(ms);
retval = bf.Deserialize(ms);
ms.Close();
}
return (T)retval; return (T)retval;
} }
@@ -917,15 +918,15 @@ namespace v2rayN
/// 获取剪贴板数 /// 获取剪贴板数
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static string GetClipboardData() public static string? GetClipboardData()
{ {
string strData = string.Empty; string? strData = string.Empty;
try try
{ {
IDataObject data = Clipboard.GetDataObject(); IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.UnicodeText)) if (data.GetDataPresent(DataFormats.UnicodeText))
{ {
strData = data.GetData(DataFormats.UnicodeText).ToString(); strData = data.GetData(DataFormats.UnicodeText)?.ToString();
} }
return strData; return strData;
} }
@@ -995,7 +996,6 @@ namespace v2rayN
} }
} }
public static string GetDownloadFileName(string url) public static string GetDownloadFileName(string url)
{ {
var fileName = Path.GetFileName(url); var fileName = Path.GetFileName(url);
@@ -1004,7 +1004,7 @@ namespace v2rayN
return fileName; return fileName;
} }
public static IPAddress GetDefaultGateway() public static IPAddress? GetDefaultGateway()
{ {
return NetworkInterface return NetworkInterface
.GetAllNetworkInterfaces() .GetAllNetworkInterfaces()
@@ -1022,6 +1022,7 @@ namespace v2rayN
{ {
return Guid.TryParse(strSrc, out Guid g); return Guid.TryParse(strSrc, out Guid g);
} }
public static void ProcessStart(string fileName) public static void ProcessStart(string fileName)
{ {
try try
@@ -1043,7 +1044,8 @@ namespace v2rayN
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize); DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize);
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize); DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize);
} }
#endregion
#endregion
#region TempPath #region TempPath
@@ -1067,14 +1069,11 @@ namespace v2rayN
public static string UnGzip(byte[] buf) public static string UnGzip(byte[] buf)
{ {
MemoryStream sb = new MemoryStream(); using MemoryStream sb = new();
using (GZipStream input = new GZipStream(new MemoryStream(buf), using GZipStream input = new(new MemoryStream(buf), CompressionMode.Decompress, false);
CompressionMode.Decompress, input.CopyTo(sb);
false)) sb.Position = 0;
{ return new StreamReader(sb, Encoding.UTF8).ReadToEnd();
input.CopyTo(sb);
}
return Encoding.UTF8.GetString(sb.ToArray());
} }
public static string GetBackupPath(string filename) public static string GetBackupPath(string filename)
@@ -1086,6 +1085,7 @@ namespace v2rayN
} }
return Path.Combine(_tempPath, filename); return Path.Combine(_tempPath, filename);
} }
public static string GetConfigPath(string filename = "") public static string GetConfigPath(string filename = "")
{ {
string _tempPath = Path.Combine(StartupPath(), "guiConfigs"); string _tempPath = Path.Combine(StartupPath(), "guiConfigs");
@@ -1102,6 +1102,7 @@ namespace v2rayN
return Path.Combine(_tempPath, filename); return Path.Combine(_tempPath, filename);
} }
} }
public static string GetBinPath(string filename, ECoreType? coreType = null) public static string GetBinPath(string filename, ECoreType? coreType = null)
{ {
string _tempPath = Path.Combine(StartupPath(), "bin"); string _tempPath = Path.Combine(StartupPath(), "bin");
@@ -1117,8 +1118,16 @@ namespace v2rayN
Directory.CreateDirectory(_tempPath); Directory.CreateDirectory(_tempPath);
} }
} }
return Path.Combine(_tempPath, filename); if (string.IsNullOrEmpty(filename))
{
return _tempPath;
}
else
{
return Path.Combine(_tempPath, filename);
}
} }
public static string GetLogPath(string filename = "") public static string GetLogPath(string filename = "")
{ {
string _tempPath = Path.Combine(StartupPath(), "guiLogs"); string _tempPath = Path.Combine(StartupPath(), "guiLogs");
@@ -1136,74 +1145,92 @@ namespace v2rayN
} }
} }
#endregion public static string GetFontsPath(string filename = "")
{
string _tempPath = Path.Combine(StartupPath(), "guiFonts");
if (!Directory.Exists(_tempPath))
{
Directory.CreateDirectory(_tempPath);
}
if (string.IsNullOrEmpty(filename))
{
return _tempPath;
}
else
{
return Path.Combine(_tempPath, filename);
}
}
#endregion TempPath
#region Log #region Log
public static void SaveLog(string strContent) public static void SaveLog(string strContent)
{ {
var logger = LogManager.GetLogger("Log1"); if (LogManager.IsLoggingEnabled())
logger.Info(strContent);
}
public static void SaveLog(string strTitle, Exception ex)
{
var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace);
if (ex != null && ex.InnerException != null)
{ {
logger.Error(ex.InnerException); var logger = LogManager.GetLogger("Log1");
logger.Info(strContent);
} }
} }
#endregion 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?.InnerException != null)
{
logger.Error(ex.InnerException);
}
}
}
#endregion Log
#region scan screen #region scan screen
public static string ScanScreen() public static string ScanScreen(float dpiX, float dpiY)
{ {
try try
{ {
foreach (Screen screen in Screen.AllScreens) 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))
{ {
using (Bitmap fullImage = new Bitmap(screen.Bounds.Width, g.CopyFromScreen(left, top, 0, 0, fullImage.Size, CopyPixelOperation.SourceCopy);
screen.Bounds.Height)) }
int maxTry = 10;
for (int i = 0; i < maxTry; i++)
{
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
Rectangle cropRect = new(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new(width, height);
double imageScale = (double)width / (double)cropRect.Width;
using (Graphics g = Graphics.FromImage(target))
{ {
using (Graphics g = Graphics.FromImage(fullImage)) g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
{ cropRect,
g.CopyFromScreen(screen.Bounds.X, GraphicsUnit.Pixel);
screen.Bounds.Y, }
0, 0,
fullImage.Size,
CopyPixelOperation.SourceCopy);
}
int maxTry = 10;
for (int i = 0; i < maxTry; i++)
{
int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width; BitmapLuminanceSource source = new(target);
using (Graphics g = Graphics.FromImage(target)) BinaryBitmap bitmap = new(new HybridBinarizer(source));
{ QRCodeReader reader = new();
g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height), Result result = reader.decode(bitmap);
cropRect, if (result != null)
GraphicsUnit.Pixel); {
} string ret = result.Text;
return ret;
BitmapLuminanceSource source = new BitmapLuminanceSource(target);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
Result result = reader.decode(bitmap);
if (result != null)
{
string ret = result.Text;
return ret;
}
}
} }
} }
} }
@@ -1214,12 +1241,18 @@ namespace v2rayN
return string.Empty; return string.Empty;
} }
#endregion 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 scan screen
#region Windows API #region Windows API
[Flags] [Flags]
public enum DWMWINDOWATTRIBUTE : uint public enum DWMWINDOWATTRIBUTE : uint
{ {
@@ -1230,6 +1263,6 @@ namespace v2rayN
[DllImport("dwmapi.dll")] [DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize); public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
#endregion #endregion Windows API
} }
} }

View File

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

View File

@@ -21,7 +21,6 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public AddServerViewModel(ProfileItem profileItem, Window view) public AddServerViewModel(ProfileItem profileItem, Window view)
{ {
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
@@ -118,6 +117,10 @@ namespace v2rayN.ViewModels
item.allowInsecure = SelectedSource.allowInsecure; item.allowInsecure = SelectedSource.allowInsecure;
item.fingerprint = SelectedSource.fingerprint; item.fingerprint = SelectedSource.fingerprint;
item.alpn = SelectedSource.alpn; item.alpn = SelectedSource.alpn;
item.publicKey = SelectedSource.publicKey;
item.shortId = SelectedSource.shortId;
item.spiderX = SelectedSource.spiderX;
} }
int ret = -1; int ret = -1;
@@ -126,15 +129,19 @@ namespace v2rayN.ViewModels
case EConfigType.VMess: case EConfigType.VMess:
ret = ConfigHandler.AddServer(ref _config, item); ret = ConfigHandler.AddServer(ref _config, item);
break; break;
case EConfigType.Shadowsocks: case EConfigType.Shadowsocks:
ret = ConfigHandler.AddShadowsocksServer(ref _config, item); ret = ConfigHandler.AddShadowsocksServer(ref _config, item);
break; break;
case EConfigType.Socks: case EConfigType.Socks:
ret = ConfigHandler.AddSocksServer(ref _config, item); ret = ConfigHandler.AddSocksServer(ref _config, item);
break; break;
case EConfigType.VLESS: case EConfigType.VLESS:
ret = ConfigHandler.AddVlessServer(ref _config, item); ret = ConfigHandler.AddVlessServer(ref _config, item);
break; break;
case EConfigType.Trojan: case EConfigType.Trojan:
ret = ConfigHandler.AddTrojanServer(ref _config, item); ret = ConfigHandler.AddTrojanServer(ref _config, item);
break; break;
@@ -152,4 +159,4 @@ namespace v2rayN.ViewModels
} }
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@ namespace v2rayN.ViewModels
private Window _view; private Window _view;
#region Core #region Core
[Reactive] public int localPort { get; set; } [Reactive] public int localPort { get; set; }
[Reactive] public bool udpEnabled { get; set; } [Reactive] public bool udpEnabled { get; set; }
[Reactive] public bool sniffingEnabled { get; set; } [Reactive] public bool sniffingEnabled { get; set; }
@@ -30,14 +31,18 @@ namespace v2rayN.ViewModels
[Reactive] public bool defAllowInsecure { get; set; } [Reactive] public bool defAllowInsecure { get; set; }
[Reactive] public string defFingerprint { get; set; } [Reactive] public string defFingerprint { get; set; }
[Reactive] public string defUserAgent { get; set; } [Reactive] public string defUserAgent { get; set; }
#endregion
#endregion Core
#region Core DNS #region Core DNS
[Reactive] public string domainStrategy4Freedom { get; set; } [Reactive] public string domainStrategy4Freedom { get; set; }
[Reactive] public string remoteDNS { get; set; } [Reactive] public string remoteDNS { get; set; }
#endregion
#endregion Core DNS
#region Core KCP #region Core KCP
//[Reactive] public int Kcpmtu { get; set; } //[Reactive] public int Kcpmtu { get; set; }
//[Reactive] public int Kcptti { get; set; } //[Reactive] public int Kcptti { get; set; }
//[Reactive] public int KcpuplinkCapacity { get; set; } //[Reactive] public int KcpuplinkCapacity { get; set; }
@@ -45,9 +50,11 @@ namespace v2rayN.ViewModels
//[Reactive] public int KcpreadBufferSize { get; set; } //[Reactive] public int KcpreadBufferSize { get; set; }
//[Reactive] public int KcpwriteBufferSize { get; set; } //[Reactive] public int KcpwriteBufferSize { get; set; }
//[Reactive] public bool Kcpcongestion { get; set; } //[Reactive] public bool Kcpcongestion { get; set; }
#endregion
#endregion Core KCP
#region UI #region UI
[Reactive] public bool AutoRun { get; set; } [Reactive] public bool AutoRun { get; set; }
[Reactive] public bool EnableStatistics { get; set; } [Reactive] public bool EnableStatistics { get; set; }
[Reactive] public int StatisticsFreshRate { get; set; } [Reactive] public int StatisticsFreshRate { get; set; }
@@ -60,28 +67,43 @@ namespace v2rayN.ViewModels
[Reactive] public bool EnableDragDropSort { get; set; } [Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; } [Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int autoUpdateInterval { get; set; } [Reactive] public int autoUpdateInterval { get; set; }
[Reactive] public int autoUpdateSubInterval { get; set; }
[Reactive] public int trayMenuServersLimit { get; set; } [Reactive] public int trayMenuServersLimit { get; set; }
[Reactive] public string currentFontFamily { get; set; } [Reactive] public string currentFontFamily { get; set; }
[Reactive] public int SpeedTestTimeout { get; set; }
[Reactive] public string SpeedTestUrl { get; set; }
[Reactive] public bool EnableHWA { get; set; }
[Reactive] public string SubConvertUrl { get; set; }
#endregion #endregion UI
#region System proxy #region System proxy
[Reactive] public string systemProxyAdvancedProtocol { get; set; } [Reactive] public string systemProxyAdvancedProtocol { get; set; }
[Reactive] public string systemProxyExceptions { get; set; } [Reactive] public string systemProxyExceptions { get; set; }
#endregion
#endregion System proxy
#region Tun mode #region Tun mode
[Reactive] public bool TunShowWindow { get; set; } [Reactive] public bool TunShowWindow { get; set; }
[Reactive] public bool TunEnabledLog { get; set; }
[Reactive] public bool TunStrictRoute { get; set; } [Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; } [Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
[Reactive] public string TunCustomTemplate { get; set; } [Reactive] public string TunCustomTemplate { get; set; }
[Reactive] public bool TunBypassMode { get; set; }
[Reactive] public bool TunBypassMode2 { get; set; }
[Reactive] public string TunDirectIP { get; set; } [Reactive] public string TunDirectIP { get; set; }
[Reactive] public string TunDirectProcess { get; set; } [Reactive] public string TunDirectProcess { get; set; }
#endregion [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 Tun mode
#region CoreType #region CoreType
[Reactive] public string CoreType1 { get; set; } [Reactive] public string CoreType1 { get; set; }
[Reactive] public string CoreType2 { get; set; } [Reactive] public string CoreType2 { get; set; }
[Reactive] public string CoreType3 { get; set; } [Reactive] public string CoreType3 { get; set; }
@@ -89,11 +111,10 @@ namespace v2rayN.ViewModels
[Reactive] public string CoreType5 { get; set; } [Reactive] public string CoreType5 { get; set; }
[Reactive] public string CoreType6 { get; set; } [Reactive] public string CoreType6 { get; set; }
#endregion #endregion CoreType
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public OptionSettingViewModel(Window view) public OptionSettingViewModel(Window view)
{ {
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
@@ -101,6 +122,7 @@ namespace v2rayN.ViewModels
_view = view; _view = view;
#region Core #region Core
var inbound = _config.inbound[0]; var inbound = _config.inbound[0];
localPort = inbound.localPort; localPort = inbound.localPort;
udpEnabled = inbound.udpEnabled; udpEnabled = inbound.udpEnabled;
@@ -110,20 +132,24 @@ namespace v2rayN.ViewModels
newPort4LAN = inbound.newPort4LAN; newPort4LAN = inbound.newPort4LAN;
user = inbound.user; user = inbound.user;
pass = inbound.pass; pass = inbound.pass;
muxEnabled = _config.muxEnabled; muxEnabled = _config.coreBasicItem.muxEnabled;
logEnabled = _config.logEnabled; logEnabled = _config.coreBasicItem.logEnabled;
loglevel = _config.loglevel; loglevel = _config.coreBasicItem.loglevel;
defAllowInsecure = _config.defAllowInsecure; defAllowInsecure = _config.coreBasicItem.defAllowInsecure;
defFingerprint = _config.defFingerprint; defFingerprint = _config.coreBasicItem.defFingerprint;
defUserAgent = _config.defUserAgent; defUserAgent = _config.coreBasicItem.defUserAgent;
#endregion
#endregion Core
#region Core DNS #region Core DNS
domainStrategy4Freedom = _config.domainStrategy4Freedom; domainStrategy4Freedom = _config.domainStrategy4Freedom;
remoteDNS = _config.remoteDNS; remoteDNS = _config.remoteDNS;
#endregion
#endregion Core DNS
#region Core KCP #region Core KCP
//Kcpmtu = _config.kcpItem.mtu; //Kcpmtu = _config.kcpItem.mtu;
//Kcptti = _config.kcpItem.tti; //Kcptti = _config.kcpItem.tti;
//KcpuplinkCapacity = _config.kcpItem.uplinkCapacity; //KcpuplinkCapacity = _config.kcpItem.uplinkCapacity;
@@ -131,43 +157,59 @@ namespace v2rayN.ViewModels
//KcpreadBufferSize = _config.kcpItem.readBufferSize; //KcpreadBufferSize = _config.kcpItem.readBufferSize;
//KcpwriteBufferSize = _config.kcpItem.writeBufferSize; //KcpwriteBufferSize = _config.kcpItem.writeBufferSize;
//Kcpcongestion = _config.kcpItem.congestion; //Kcpcongestion = _config.kcpItem.congestion;
#endregion
#endregion Core KCP
#region UI #region UI
AutoRun = _config.autoRun;
EnableStatistics = _config.enableStatistics; AutoRun = _config.guiItem.autoRun;
StatisticsFreshRate = _config.statisticsFreshRate; EnableStatistics = _config.guiItem.enableStatistics;
KeepOlderDedupl = _config.keepOlderDedupl; StatisticsFreshRate = _config.guiItem.statisticsFreshRate;
IgnoreGeoUpdateCore = _config.ignoreGeoUpdateCore; KeepOlderDedupl = _config.guiItem.keepOlderDedupl;
IgnoreGeoUpdateCore = _config.guiItem.ignoreGeoUpdateCore;
EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth; EnableAutoAdjustMainLvColWidth = _config.uiItem.enableAutoAdjustMainLvColWidth;
EnableSecurityProtocolTls13 = _config.enableSecurityProtocolTls13; EnableSecurityProtocolTls13 = _config.guiItem.enableSecurityProtocolTls13;
AutoHideStartup = _config.uiItem.autoHideStartup; AutoHideStartup = _config.uiItem.autoHideStartup;
EnableCheckPreReleaseUpdate = _config.checkPreReleaseUpdate; EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate;
EnableDragDropSort = _config.uiItem.enableDragDropSort; EnableDragDropSort = _config.uiItem.enableDragDropSort;
DoubleClick2Activate = _config.uiItem.doubleClick2Activate; DoubleClick2Activate = _config.uiItem.doubleClick2Activate;
autoUpdateInterval = _config.autoUpdateInterval; autoUpdateInterval = _config.guiItem.autoUpdateInterval;
autoUpdateSubInterval = _config.autoUpdateSubInterval; trayMenuServersLimit = _config.guiItem.trayMenuServersLimit;
trayMenuServersLimit = _config.trayMenuServersLimit;
currentFontFamily = _config.uiItem.currentFontFamily; currentFontFamily = _config.uiItem.currentFontFamily;
SpeedTestTimeout = _config.speedTestItem.speedTestTimeout;
SpeedTestUrl = _config.speedTestItem.speedTestUrl;
EnableHWA = _config.guiItem.enableHWA;
SubConvertUrl = _config.constItem.subConvertUrl;
#endregion #endregion UI
#region System proxy #region System proxy
systemProxyAdvancedProtocol = _config.systemProxyAdvancedProtocol; systemProxyAdvancedProtocol = _config.systemProxyAdvancedProtocol;
systemProxyExceptions = _config.systemProxyExceptions; systemProxyExceptions = _config.systemProxyExceptions;
#endregion
#endregion System proxy
#region Tun mode #region Tun mode
TunShowWindow = _config.tunModeItem.showWindow; TunShowWindow = _config.tunModeItem.showWindow;
TunEnabledLog = _config.tunModeItem.enabledLog;
TunStrictRoute = _config.tunModeItem.strictRoute; TunStrictRoute = _config.tunModeItem.strictRoute;
TunStack = _config.tunModeItem.stack; TunStack = _config.tunModeItem.stack;
TunMtu = _config.tunModeItem.mtu; TunMtu = _config.tunModeItem.mtu;
TunCustomTemplate = _config.tunModeItem.customTemplate; TunCustomTemplate = _config.tunModeItem.customTemplate;
TunBypassMode = _config.tunModeItem.bypassMode;
TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true); TunDirectIP = Utils.List2String(_config.tunModeItem.directIP, true);
TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true); TunDirectProcess = Utils.List2String(_config.tunModeItem.directProcess, true);
TunDirectDNS = _config.tunModeItem.directDNS;
TunProxyIP = Utils.List2String(_config.tunModeItem.proxyIP, true);
TunProxyProcess = Utils.List2String(_config.tunModeItem.proxyProcess, true);
TunProxyDNS = _config.tunModeItem.proxyDNS;
this.WhenAnyValue(
x => x.TunBypassMode)
.Subscribe(c => TunBypassMode2 = !TunBypassMode);
#endregion #endregion Tun mode
InitCoreType(); InitCoreType();
@@ -207,18 +249,23 @@ namespace v2rayN.ViewModels
case 1: case 1:
CoreType1 = type; CoreType1 = type;
break; break;
case 2: case 2:
CoreType2 = type; CoreType2 = type;
break; break;
case 3: case 3:
CoreType3 = type; CoreType3 = type;
break; break;
case 4: case 4:
CoreType4 = type; CoreType4 = type;
break; break;
case 5: case 5:
CoreType5 = type; CoreType5 = type;
break; break;
case 6: case 6:
CoreType6 = type; CoreType6 = type;
break; break;
@@ -226,7 +273,6 @@ namespace v2rayN.ViewModels
}); });
} }
private void SaveSetting() private void SaveSetting()
{ {
if (Utils.IsNullOrEmpty(localPort.ToString()) || !Utils.IsNumberic(localPort.ToString()) if (Utils.IsNullOrEmpty(localPort.ToString()) || !Utils.IsNumberic(localPort.ToString())
@@ -237,7 +283,7 @@ namespace v2rayN.ViewModels
} }
var obj = Utils.ParseJson(remoteDNS); var obj = Utils.ParseJson(remoteDNS);
if (obj != null && obj.ContainsKey("servers")) if (obj?.ContainsKey("servers") == true)
{ {
} }
else else
@@ -261,7 +307,7 @@ namespace v2rayN.ViewModels
//} //}
//Core //Core
_config.inbound[0].localPort = Utils.ToInt(localPort); _config.inbound[0].localPort = localPort;
_config.inbound[0].udpEnabled = udpEnabled; _config.inbound[0].udpEnabled = udpEnabled;
_config.inbound[0].sniffingEnabled = sniffingEnabled; _config.inbound[0].sniffingEnabled = sniffingEnabled;
_config.inbound[0].routeOnly = routeOnly; _config.inbound[0].routeOnly = routeOnly;
@@ -273,19 +319,17 @@ namespace v2rayN.ViewModels
{ {
_config.inbound.RemoveAt(1); _config.inbound.RemoveAt(1);
} }
_config.logEnabled = logEnabled; _config.coreBasicItem.logEnabled = logEnabled;
_config.loglevel = loglevel; _config.coreBasicItem.loglevel = loglevel;
_config.muxEnabled = muxEnabled; _config.coreBasicItem.muxEnabled = muxEnabled;
_config.defAllowInsecure = defAllowInsecure; _config.coreBasicItem.defAllowInsecure = defAllowInsecure;
_config.defFingerprint = defFingerprint; _config.coreBasicItem.defFingerprint = defFingerprint;
_config.defUserAgent = defUserAgent; _config.coreBasicItem.defUserAgent = defUserAgent;
//DNS //DNS
_config.remoteDNS = remoteDNS; _config.remoteDNS = remoteDNS;
_config.domainStrategy4Freedom = domainStrategy4Freedom; _config.domainStrategy4Freedom = domainStrategy4Freedom;
//Kcp //Kcp
//_config.kcpItem.mtu = Kcpmtu; //_config.kcpItem.mtu = Kcpmtu;
//_config.kcpItem.tti = Kcptti; //_config.kcpItem.tti = Kcptti;
@@ -295,28 +339,30 @@ namespace v2rayN.ViewModels
//_config.kcpItem.writeBufferSize = KcpwriteBufferSize; //_config.kcpItem.writeBufferSize = KcpwriteBufferSize;
//_config.kcpItem.congestion = Kcpcongestion; //_config.kcpItem.congestion = Kcpcongestion;
//UI //UI
Utils.SetAutoRun(AutoRun); Utils.SetAutoRun(AutoRun);
_config.autoRun = AutoRun; _config.guiItem.autoRun = AutoRun;
_config.enableStatistics = EnableStatistics; _config.guiItem.enableStatistics = EnableStatistics;
_config.statisticsFreshRate = StatisticsFreshRate; _config.guiItem.statisticsFreshRate = StatisticsFreshRate;
if (_config.statisticsFreshRate > 100 || _config.statisticsFreshRate < 1) if (_config.guiItem.statisticsFreshRate > 100 || _config.guiItem.statisticsFreshRate < 1)
{ {
_config.statisticsFreshRate = 1; _config.guiItem.statisticsFreshRate = 1;
} }
_config.keepOlderDedupl = KeepOlderDedupl; _config.guiItem.keepOlderDedupl = KeepOlderDedupl;
_config.ignoreGeoUpdateCore = IgnoreGeoUpdateCore; _config.guiItem.ignoreGeoUpdateCore = IgnoreGeoUpdateCore;
_config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth; _config.uiItem.enableAutoAdjustMainLvColWidth = EnableAutoAdjustMainLvColWidth;
_config.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13; _config.guiItem.enableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.uiItem.autoHideStartup = AutoHideStartup; _config.uiItem.autoHideStartup = AutoHideStartup;
_config.autoUpdateInterval = autoUpdateInterval; _config.guiItem.autoUpdateInterval = autoUpdateInterval;
_config.autoUpdateSubInterval = autoUpdateSubInterval; _config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.uiItem.enableDragDropSort = EnableDragDropSort; _config.uiItem.enableDragDropSort = EnableDragDropSort;
_config.uiItem.doubleClick2Activate = DoubleClick2Activate; _config.uiItem.doubleClick2Activate = DoubleClick2Activate;
_config.trayMenuServersLimit = trayMenuServersLimit; _config.guiItem.trayMenuServersLimit = trayMenuServersLimit;
_config.uiItem.currentFontFamily = currentFontFamily; _config.uiItem.currentFontFamily = currentFontFamily;
_config.speedTestItem.speedTestTimeout = SpeedTestTimeout;
_config.speedTestItem.speedTestUrl = SpeedTestUrl;
_config.guiItem.enableHWA = EnableHWA;
_config.constItem.subConvertUrl = SubConvertUrl;
//systemProxy //systemProxy
_config.systemProxyExceptions = systemProxyExceptions; _config.systemProxyExceptions = systemProxyExceptions;
@@ -324,14 +370,20 @@ namespace v2rayN.ViewModels
//tun mode //tun mode
_config.tunModeItem.showWindow = TunShowWindow; _config.tunModeItem.showWindow = TunShowWindow;
_config.tunModeItem.enabledLog = TunEnabledLog;
_config.tunModeItem.strictRoute = TunStrictRoute; _config.tunModeItem.strictRoute = TunStrictRoute;
_config.tunModeItem.stack = TunStack; _config.tunModeItem.stack = TunStack;
_config.tunModeItem.mtu = TunMtu; _config.tunModeItem.mtu = TunMtu;
_config.tunModeItem.customTemplate = TunCustomTemplate; _config.tunModeItem.customTemplate = TunCustomTemplate;
_config.tunModeItem.bypassMode = TunBypassMode;
_config.tunModeItem.directIP = Utils.String2List(TunDirectIP); _config.tunModeItem.directIP = Utils.String2List(TunDirectIP);
_config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess); _config.tunModeItem.directProcess = Utils.String2List(TunDirectProcess);
_config.tunModeItem.directDNS = Utils.ToJson(Utils.ParseJson(TunDirectDNS));
_config.tunModeItem.proxyIP = Utils.String2List(TunProxyIP);
_config.tunModeItem.proxyProcess = Utils.String2List(TunProxyProcess);
_config.tunModeItem.proxyDNS = Utils.ToJson(Utils.ParseJson(TunProxyDNS));
//coreType //coreType
SaveCoreType(); SaveCoreType();
if (ConfigHandler.SaveConfig(ref _config) == 0) if (ConfigHandler.SaveConfig(ref _config) == 0)
@@ -343,8 +395,8 @@ namespace v2rayN.ViewModels
{ {
UI.ShowWarning(ResUI.OperationFailed); UI.ShowWarning(ResUI.OperationFailed);
} }
} }
private int SaveCoreType() private int SaveCoreType()
{ {
for (int k = 1; k <= _config.coreTypeItem.Count; k++) for (int k = 1; k <= _config.coreTypeItem.Count; k++)
@@ -356,18 +408,23 @@ namespace v2rayN.ViewModels
case 1: case 1:
type = CoreType1; type = CoreType1;
break; break;
case 2: case 2:
type = CoreType2; type = CoreType2;
break; break;
case 3: case 3:
type = CoreType3; type = CoreType3;
break; break;
case 4: case 4:
type = CoreType4; type = CoreType4;
break; break;
case 5: case 5:
type = CoreType5; type = CoreType5;
break; break;
case 6: case 6:
type = CoreType6; type = CoreType6;
break; break;
@@ -377,4 +434,4 @@ namespace v2rayN.ViewModels
return 0; return 0;
} }
} }
} }

View File

@@ -31,10 +31,8 @@ namespace v2rayN.ViewModels
[Reactive] [Reactive]
public bool AutoSort { get; set; } public bool AutoSort { get; set; }
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public RoutingRuleDetailsViewModel(RulesItem rulesItem, Window view) public RoutingRuleDetailsViewModel(RulesItem rulesItem, Window view)
{ {
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
@@ -63,6 +61,7 @@ namespace v2rayN.ViewModels
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
} }
private void SaveRules() private void SaveRules()
{ {
if (AutoSort) if (AutoSort)
@@ -96,4 +95,4 @@ namespace v2rayN.ViewModels
_view.DialogResult = true; _view.DialogResult = true;
} }
} }
} }

View File

@@ -1,10 +1,10 @@
using DynamicData.Binding; using DynamicData.Binding;
using Microsoft.Win32;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive; using System.Reactive;
using System.Windows; using System.Windows;
using System.Windows.Forms;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
@@ -26,8 +26,10 @@ namespace v2rayN.ViewModels
private IObservableCollection<RulesItemModel> _rulesItems = new ObservableCollectionExtended<RulesItemModel>(); private IObservableCollection<RulesItemModel> _rulesItems = new ObservableCollectionExtended<RulesItemModel>();
public IObservableCollection<RulesItemModel> RulesItems => _rulesItems; public IObservableCollection<RulesItemModel> RulesItems => _rulesItems;
[Reactive] [Reactive]
public RulesItemModel SelectedSource { get; set; } public RulesItemModel SelectedSource { get; set; }
public IList<RulesItemModel> SelectedSources { get; set; } public IList<RulesItemModel> SelectedSources { get; set; }
public ReactiveCommand<Unit, Unit> RuleAddCmd { get; } public ReactiveCommand<Unit, Unit> RuleAddCmd { get; }
@@ -43,7 +45,6 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public RoutingRuleSettingViewModel(RoutingItem routingItem, Window view) public RoutingRuleSettingViewModel(RoutingItem routingItem, Window view)
{ {
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
@@ -173,7 +174,7 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.PleaseSelectRules); UI.Show(ResUI.PleaseSelectRules);
return; return;
} }
if (UI.ShowYesNo(ResUI.RemoveRules) == DialogResult.No) if (UI.ShowYesNo(ResUI.RemoveRules) == MessageBoxResult.No)
{ {
return; return;
} }
@@ -188,6 +189,7 @@ namespace v2rayN.ViewModels
RefreshRulesItems(); RefreshRulesItems();
} }
public void RuleExportSelected() public void RuleExportSelected()
{ {
if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty()) if (SelectedSource is null || SelectedSource.outboundTag.IsNullOrEmpty())
@@ -268,7 +270,7 @@ namespace v2rayN.ViewModels
Multiselect = false, Multiselect = false,
Filter = "Rules|*.json|All|*.*" Filter = "Rules|*.json|All|*.*"
}; };
if (fileDialog.ShowDialog() != DialogResult.OK) if (fileDialog.ShowDialog() != true)
{ {
return; return;
} }
@@ -299,7 +301,8 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.OperationSuccess); UI.Show(ResUI.OperationSuccess);
} }
} }
private void ImportRulesFromUrl()
private async Task ImportRulesFromUrl()
{ {
var url = SelectedRouting.url; var url = SelectedRouting.url;
if (Utils.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
@@ -308,24 +311,22 @@ namespace v2rayN.ViewModels
return; return;
} }
Task.Run(async () => DownloadHandle downloadHandle = new DownloadHandle();
string result = await downloadHandle.TryDownloadString(url, true, "");
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{ {
DownloadHandle downloadHandle = new DownloadHandle(); Application.Current.Dispatcher.Invoke((Action)(() =>
string result = await downloadHandle.DownloadStringAsync(url, false, "");
if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{ {
Application.Current.Dispatcher.Invoke((Action)(() => RefreshRulesItems();
{ }));
RefreshRulesItems(); UI.Show(ResUI.OperationSuccess);
})); }
UI.Show(ResUI.OperationSuccess);
}
});
} }
private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData) private int AddBatchRoutingRules(RoutingItem routingItem, string clipboardData)
{ {
bool blReplace = false; bool blReplace = false;
if (UI.ShowYesNo(ResUI.AddBatchRoutingRulesYesNo) == DialogResult.No) if (UI.ShowYesNo(ResUI.AddBatchRoutingRulesYesNo) == MessageBoxResult.No)
{ {
blReplace = true; blReplace = true;
} }
@@ -354,6 +355,6 @@ namespace v2rayN.ViewModels
return 0; return 0;
} }
#endregion #endregion Import rules
} }
} }

View File

@@ -4,7 +4,6 @@ using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive; using System.Reactive;
using System.Windows; using System.Windows;
using System.Windows.Forms;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
@@ -21,34 +20,43 @@ namespace v2rayN.ViewModels
private RoutingItem _lockedItem; private RoutingItem _lockedItem;
private List<RulesItem> _lockedRules; private List<RulesItem> _lockedRules;
#region Reactive #region Reactive
private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>(); private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>();
public IObservableCollection<RoutingItemModel> RoutingItems => _routingItems; public IObservableCollection<RoutingItemModel> RoutingItems => _routingItems;
[Reactive] [Reactive]
public RoutingItemModel SelectedSource { get; set; } public RoutingItemModel SelectedSource { get; set; }
public IList<RoutingItemModel> SelectedSources { get; set; } public IList<RoutingItemModel> SelectedSources { get; set; }
[Reactive] [Reactive]
public bool enableRoutingAdvanced { get; set; } public bool enableRoutingAdvanced { get; set; }
[Reactive] [Reactive]
public bool enableRoutingBasic { get; set; } public bool enableRoutingBasic { get; set; }
[Reactive] [Reactive]
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
[Reactive] [Reactive]
public string domainMatcher { get; set; } public string domainMatcher { get; set; }
[Reactive] [Reactive]
public string ProxyDomain { get; set; } public string ProxyDomain { get; set; }
[Reactive] [Reactive]
public string ProxyIP { get; set; } public string ProxyIP { get; set; }
[Reactive] [Reactive]
public string DirectDomain { get; set; } public string DirectDomain { get; set; }
[Reactive] [Reactive]
public string DirectIP { get; set; } public string DirectIP { get; set; }
[Reactive] [Reactive]
public string BlockDomain { get; set; } public string BlockDomain { get; set; }
[Reactive] [Reactive]
public string BlockIP { get; set; } public string BlockIP { get; set; }
@@ -60,7 +68,8 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public bool IsModified { get; set; } public bool IsModified { get; set; }
#endregion
#endregion Reactive
public RoutingSettingViewModel(Window view) public RoutingSettingViewModel(Window view)
{ {
@@ -71,9 +80,9 @@ namespace v2rayN.ViewModels
ConfigHandler.InitBuiltinRouting(ref _config); ConfigHandler.InitBuiltinRouting(ref _config);
enableRoutingAdvanced = _config.enableRoutingAdvanced; enableRoutingAdvanced = _config.routingBasicItem.enableRoutingAdvanced;
domainStrategy = _config.domainStrategy; domainStrategy = _config.routingBasicItem.domainStrategy;
domainMatcher = _config.domainMatcher; domainMatcher = _config.routingBasicItem.domainMatcher;
RefreshRoutingItems(); RefreshRoutingItems();
@@ -118,6 +127,7 @@ namespace v2rayN.ViewModels
} }
#region locked #region locked
private void BindingLockedData() private void BindingLockedData()
{ {
_lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config); _lockedItem = ConfigHandler.GetLockedRoutingItem(ref _config);
@@ -134,6 +144,7 @@ namespace v2rayN.ViewModels
BlockIP = Utils.List2String(_lockedRules[2].ip, true); BlockIP = Utils.List2String(_lockedRules[2].ip, true);
} }
} }
private void EndBindingLockedData() private void EndBindingLockedData()
{ {
if (_lockedItem != null) if (_lockedItem != null)
@@ -152,9 +163,11 @@ namespace v2rayN.ViewModels
ConfigHandler.SaveRoutingItem(ref _config, _lockedItem); ConfigHandler.SaveRoutingItem(ref _config, _lockedItem);
} }
} }
#endregion
#endregion locked
#region Refresh Save #region Refresh Save
public void RefreshRoutingItems() public void RefreshRoutingItems()
{ {
_routingItems.Clear(); _routingItems.Clear();
@@ -163,7 +176,7 @@ namespace v2rayN.ViewModels
foreach (var item in routings) foreach (var item in routings)
{ {
bool def = false; bool def = false;
if (item.id.Equals(_config.routingIndexId)) if (item.id == _config.routingBasicItem.routingIndexId)
{ {
def = true; def = true;
} }
@@ -176,15 +189,17 @@ namespace v2rayN.ViewModels
remarks = item.remarks, remarks = item.remarks,
url = item.url, url = item.url,
customIcon = item.customIcon, customIcon = item.customIcon,
sort = item.sort,
}; };
_routingItems.Add(it); _routingItems.Add(it);
} }
} }
private void SaveRouting() private void SaveRouting()
{ {
_config.domainStrategy = domainStrategy; _config.routingBasicItem.domainStrategy = domainStrategy;
_config.enableRoutingAdvanced = enableRoutingAdvanced; _config.routingBasicItem.enableRoutingAdvanced = enableRoutingAdvanced;
_config.domainMatcher = domainMatcher; _config.routingBasicItem.domainMatcher = domainMatcher;
EndBindingLockedData(); EndBindingLockedData();
@@ -199,7 +214,7 @@ namespace v2rayN.ViewModels
} }
} }
#endregion #endregion Refresh Save
private void RoutingBasicImportRules() private void RoutingBasicImportRules()
{ {
@@ -243,7 +258,7 @@ namespace v2rayN.ViewModels
UI.Show(ResUI.PleaseSelectRules); UI.Show(ResUI.PleaseSelectRules);
return; return;
} }
if (UI.ShowYesNo(ResUI.RemoveRules) == DialogResult.No) if (UI.ShowYesNo(ResUI.RemoveRules) == MessageBoxResult.No)
{ {
return; return;
} }
@@ -275,6 +290,7 @@ namespace v2rayN.ViewModels
IsModified = true; IsModified = true;
} }
} }
private void RoutingAdvancedImportRules() private void RoutingAdvancedImportRules()
{ {
if (ConfigHandler.InitBuiltinRouting(ref _config, true) == 0) if (ConfigHandler.InitBuiltinRouting(ref _config, true) == 0)
@@ -284,4 +300,4 @@ namespace v2rayN.ViewModels
} }
} }
} }
} }

View File

@@ -21,7 +21,6 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public SubEditViewModel(SubItem subItem, Window view) public SubEditViewModel(SubItem subItem, Window view)
{ {
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
@@ -44,6 +43,7 @@ namespace v2rayN.ViewModels
Utils.SetDarkBorder(view, _config.uiItem.colorModeDark); Utils.SetDarkBorder(view, _config.uiItem.colorModeDark);
} }
private void SaveSub() private void SaveSub()
{ {
string remarks = SelectedSource.remarks; string remarks = SelectedSource.remarks;
@@ -62,10 +62,13 @@ namespace v2rayN.ViewModels
{ {
item.remarks = SelectedSource.remarks; item.remarks = SelectedSource.remarks;
item.url = SelectedSource.url; item.url = SelectedSource.url;
item.moreUrl = SelectedSource.moreUrl;
item.enabled = SelectedSource.enabled; item.enabled = SelectedSource.enabled;
item.autoUpdateInterval = SelectedSource.autoUpdateInterval;
item.userAgent = SelectedSource.userAgent; item.userAgent = SelectedSource.userAgent;
item.sort = SelectedSource.sort; item.sort = SelectedSource.sort;
item.filter = SelectedSource.filter; item.filter = SelectedSource.filter;
item.convertTarget = SelectedSource.convertTarget;
} }
if (ConfigHandler.AddSubItem(ref _config, item) == 0) if (ConfigHandler.AddSubItem(ref _config, item) == 0)
@@ -80,4 +83,4 @@ namespace v2rayN.ViewModels
} }
} }
} }
} }

View File

@@ -6,7 +6,6 @@ using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive; using System.Reactive;
using System.Windows; using System.Windows;
using System.Windows.Forms;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
@@ -22,9 +21,12 @@ namespace v2rayN.ViewModels
private IObservableCollection<SubItem> _subItems = new ObservableCollectionExtended<SubItem>(); private IObservableCollection<SubItem> _subItems = new ObservableCollectionExtended<SubItem>();
public IObservableCollection<SubItem> SubItems => _subItems; public IObservableCollection<SubItem> SubItems => _subItems;
[Reactive] [Reactive]
public SubItem SelectedSource { get; set; } public SubItem SelectedSource { get; set; }
public IList<SubItem> SelectedSources { get; set; }
public ReactiveCommand<Unit, Unit> SubAddCmd { get; } public ReactiveCommand<Unit, Unit> SubAddCmd { get; }
public ReactiveCommand<Unit, Unit> SubDeleteCmd { get; } public ReactiveCommand<Unit, Unit> SubDeleteCmd { get; }
public ReactiveCommand<Unit, Unit> SubEditCmd { get; } public ReactiveCommand<Unit, Unit> SubEditCmd { get; }
@@ -91,17 +93,19 @@ namespace v2rayN.ViewModels
RefreshSubItems(); RefreshSubItems();
IsModified = true; IsModified = true;
} }
} }
private void DeleteSub() private void DeleteSub()
{ {
if (UI.ShowYesNo(ResUI.RemoveServer) == DialogResult.No) if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No)
{ {
return; return;
} }
ConfigHandler.DeleteSubItem(ref _config, SelectedSource?.id); foreach (var it in SelectedSources)
{
ConfigHandler.DeleteSubItem(ref _config, it?.id);
}
RefreshSubItems(); RefreshSubItems();
_noticeHandler?.Enqueue(ResUI.OperationSuccess); _noticeHandler?.Enqueue(ResUI.OperationSuccess);
IsModified = true; IsModified = true;
@@ -122,6 +126,5 @@ namespace v2rayN.ViewModels
await DialogHost.Show(dialog, "SubDialog"); await DialogHost.Show(dialog, "SubDialog");
} }
} }
} }

View File

@@ -18,6 +18,7 @@
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
@@ -73,7 +74,7 @@
Margin="4" Margin="4"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -91,7 +92,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<StackPanel <StackPanel
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
@@ -125,6 +126,7 @@
Width="200" Width="200"
Margin="4" Margin="4"
HorizontalAlignment="Left" HorizontalAlignment="Left"
FontSize="{DynamicResource StdFontSize}"
MaxDropDownHeight="1000" MaxDropDownHeight="1000"
Style="{StaticResource MaterialDesignOutlinedComboBox}" /> Style="{StaticResource MaterialDesignOutlinedComboBox}" />
@@ -135,12 +137,18 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbDisplayLog}" /> Text="{x:Static resx:ResUI.TbDisplayLog}" />
<ToggleButton <StackPanel
x:Name="togDisplayLog"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Margin="4" 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 <TextBlock
Grid.Row="5" Grid.Row="5"
@@ -157,7 +165,7 @@
Margin="4" Margin="4"
HorizontalAlignment="Left" HorizontalAlignment="Left"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<StackPanel <StackPanel
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
@@ -169,12 +177,11 @@
Text="{x:Static resx:ResUI.TipPreSocksPort}" Text="{x:Static resx:ResUI.TipPreSocksPort}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Grid <Grid
Grid.Row="1" Grid.Row="1"
Margin="16" Margin="8"
HorizontalAlignment="Center"> HorizontalAlignment="Center">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="200" /> <ColumnDefinition Width="200" />
@@ -195,9 +202,6 @@
IsCancel="true" IsCancel="true"
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
</Grid> </Grid>
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</reactiveui:ReactiveWindow> </reactiveui:ReactiveWindow>

View File

@@ -11,6 +11,7 @@ namespace v2rayN.Views
public AddServer2Window(ProfileItem profileItem) public AddServer2Window(ProfileItem profileItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
ViewModel = new AddServer2ViewModel(profileItem, this); ViewModel = new AddServer2ViewModel(profileItem, this);
@@ -33,15 +34,14 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.BrowseServerCmd, v => v.btnBrowse).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.BrowseServerCmd, v => v.btnBrowse).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables);
}); });
} }
private void Window_Loaded(object sender, RoutedEventArgs e) private void Window_Loaded(object sender, RoutedEventArgs e)
{ {
txtRemarks.Focus(); txtRemarks.Focus();
} }
private void btnCancel_Click(object sender, System.Windows.RoutedEventArgs e) private void btnCancel_Click(object sender, System.Windows.RoutedEventArgs e)
{ {
if (ViewModel?.IsModified == true) if (ViewModel?.IsModified == true)
@@ -53,8 +53,5 @@ namespace v2rayN.Views
this.Close(); this.Close();
} }
} }
} }
} }

View File

@@ -10,12 +10,13 @@
xmlns:resx="clr-namespace:v2rayN.Resx" xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:vms="clr-namespace:v2rayN.ViewModels" xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuServers}" Title="{x:Static resx:ResUI.menuServers}"
Width="800" Width="820"
Height="800" Height="820"
x:TypeArguments="vms:AddServerViewModel" x:TypeArguments="vms:AddServerViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
@@ -83,7 +84,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -97,7 +99,8 @@
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -112,7 +115,8 @@
Grid.Column="1" Grid.Column="1"
Width="100" Width="100"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<Separator <Separator
@@ -148,7 +152,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<Button <Button
x:Name="btnGUID" x:Name="btnGUID"
Grid.Row="1" Grid.Row="1"
@@ -171,7 +176,8 @@
Grid.Column="1" Grid.Column="1"
Width="100" Width="100"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -187,7 +193,6 @@
Width="200" Width="200"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
<Grid <Grid
x:Name="gridSs" x:Name="gridSs"
@@ -216,7 +221,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -232,7 +238,6 @@
Width="300" Width="300"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
<Grid <Grid
x:Name="gridSocks" x:Name="gridSocks"
@@ -261,7 +266,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -275,8 +281,8 @@
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<Grid <Grid
x:Name="gridVLESS" x:Name="gridVLESS"
@@ -306,7 +312,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<Button <Button
x:Name="btnGUID5" x:Name="btnGUID5"
Grid.Row="1" Grid.Row="1"
@@ -344,7 +351,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<Grid <Grid
x:Name="gridTrojan" x:Name="gridTrojan"
@@ -373,7 +381,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -478,7 +487,8 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
x:Name="tipRequestHost" x:Name="tipRequestHost"
Grid.Row="3" Grid.Row="3"
@@ -500,7 +510,8 @@
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" /> Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
x:Name="tipPath" x:Name="tipPath"
Grid.Row="4" Grid.Row="4"
@@ -509,7 +520,6 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPath}" /> Text="{x:Static resx:ResUI.TbPath}" />
</Grid> </Grid>
<Separator <Separator
@@ -545,8 +555,10 @@
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
<Grid
<Grid x:Name="gridTlsMore" Grid.Row="7"> x:Name="gridTlsMore"
Grid.Row="7"
Visibility="Hidden">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -572,7 +584,8 @@
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -580,47 +593,142 @@
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" 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}" /> Text="{x:Static resx:ResUI.TbFingerprint}" />
<ComboBox <ComboBox
x:Name="cmbFingerprint" x:Name="cmbFingerprint"
Grid.Row="3" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
IsEditable="True" IsEditable="True"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAlpn}" />
<ComboBox
x:Name="cmbAlpn"
Grid.Row="3"
Grid.Column="1"
Width="200"
Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAlpn}" /> Text="{x:Static resx:ResUI.TbAllowInsecure}" />
<ComboBox <ComboBox
x:Name="cmbAlpn" x:Name="cmbAllowInsecure"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="200" Width="100"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </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 <Separator
Grid.Row="8" Grid.Row="8"
Margin="0,2" Margin="0,2"
@@ -628,7 +736,7 @@
<Grid <Grid
Grid.Row="9" Grid.Row="9"
Margin="16" Margin="8"
HorizontalAlignment="Center"> HorizontalAlignment="Center">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="200" /> <ColumnDefinition Width="200" />
@@ -651,7 +759,6 @@
IsCancel="true" IsCancel="true"
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
</Grid> </Grid>
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</reactiveui:ReactiveWindow> </reactiveui:ReactiveWindow>

View File

@@ -12,20 +12,30 @@ namespace v2rayN.Views
{ {
public partial class AddServerWindow public partial class AddServerWindow
{ {
public AddServerWindow(ProfileItem profileItem) public AddServerWindow(ProfileItem profileItem)
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Loaded += Window_Loaded; this.Loaded += Window_Loaded;
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged; cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged; cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
ViewModel = new AddServerViewModel(profileItem, this); ViewModel = new AddServerViewModel(profileItem, this);
Global.coreTypes.ForEach(it => if (profileItem.configType == EConfigType.VLESS)
{ {
cmbCoreType.Items.Add(it); Global.coreTypes4VLESS.ForEach(it =>
}); {
cmbCoreType.Items.Add(it);
});
}
else
{
Global.coreTypes.ForEach(it =>
{
cmbCoreType.Items.Add(it);
});
}
cmbCoreType.Items.Add(string.Empty); cmbCoreType.Items.Add(string.Empty);
cmbStreamSecurity.Items.Add(string.Empty); cmbStreamSecurity.Items.Add(string.Empty);
@@ -38,6 +48,7 @@ namespace v2rayN.Views
Global.fingerprints.ForEach(it => Global.fingerprints.ForEach(it =>
{ {
cmbFingerprint.Items.Add(it); cmbFingerprint.Items.Add(it);
cmbFingerprint2.Items.Add(it);
}); });
Global.allowInsecures.ForEach(it => Global.allowInsecures.ForEach(it =>
{ {
@@ -61,6 +72,7 @@ namespace v2rayN.Views
profileItem.security = Global.DefaultSecurity; profileItem.security = Global.DefaultSecurity;
} }
break; break;
case EConfigType.Shadowsocks: case EConfigType.Shadowsocks:
gridSs.Visibility = Visibility.Visible; gridSs.Visibility = Visibility.Visible;
LazyConfig.Instance.GetShadowsocksSecuritys(profileItem).ForEach(it => LazyConfig.Instance.GetShadowsocksSecuritys(profileItem).ForEach(it =>
@@ -68,13 +80,15 @@ namespace v2rayN.Views
cmbSecurity3.Items.Add(it); cmbSecurity3.Items.Add(it);
}); });
break; break;
case EConfigType.Socks: case EConfigType.Socks:
gridSocks.Visibility = Visibility.Visible; gridSocks.Visibility = Visibility.Visible;
break; break;
case EConfigType.VLESS: case EConfigType.VLESS:
gridVLESS.Visibility = Visibility.Visible; gridVLESS.Visibility = Visibility.Visible;
cmbStreamSecurity.Items.Add(Global.StreamSecurityX); cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
Global.xtlsFlows.ForEach(it => Global.flows.ForEach(it =>
{ {
cmbFlow5.Items.Add(it); cmbFlow5.Items.Add(it);
}); });
@@ -83,10 +97,10 @@ namespace v2rayN.Views
profileItem.security = Global.None; profileItem.security = Global.None;
} }
break; break;
case EConfigType.Trojan: case EConfigType.Trojan:
gridTrojan.Visibility = Visibility.Visible; gridTrojan.Visibility = Visibility.Visible;
cmbStreamSecurity.Items.Add(Global.StreamSecurityX); Global.flows.ForEach(it =>
Global.xtlsFlows.ForEach(it =>
{ {
cmbFlow6.Items.Add(it); cmbFlow6.Items.Add(it);
}); });
@@ -109,19 +123,23 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.SelectedSource.alterId, v => v.txtAlterId.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.alterId, v => v.txtAlterId.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.cmbSecurity.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.cmbSecurity.Text).DisposeWith(disposables);
break; break;
case EConfigType.Shadowsocks: case EConfigType.Shadowsocks:
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId3.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId3.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.cmbSecurity3.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.cmbSecurity3.Text).DisposeWith(disposables);
break; break;
case EConfigType.Socks: case EConfigType.Socks:
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId4.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId4.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.txtSecurity4.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.txtSecurity4.Text).DisposeWith(disposables);
break; break;
case EConfigType.VLESS: case EConfigType.VLESS:
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId5.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId5.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow5.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow5.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.txtSecurity5.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.txtSecurity5.Text).DisposeWith(disposables);
break; break;
case EConfigType.Trojan: case EConfigType.Trojan:
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId6.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId6.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow6.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow6.Text).DisposeWith(disposables);
@@ -137,9 +155,14 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.SelectedSource.allowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables); 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.fingerprint, v => v.cmbFingerprint.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.alpn, v => v.cmbAlpn.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); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
}); });
this.Title = $"{profileItem.configType}"; this.Title = $"{profileItem.configType}";
@@ -155,18 +178,27 @@ namespace v2rayN.Views
SetHeaderType(); SetHeaderType();
SetTips(); SetTips();
} }
private void CmbStreamSecurity_SelectionChanged(object sender, SelectionChangedEventArgs e) private void CmbStreamSecurity_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
var security = cmbStreamSecurity.SelectedItem.ToString(); var security = cmbStreamSecurity.SelectedItem.ToString();
if (Utils.IsNullOrEmpty(security)) if (security == Global.StreamSecurityReality)
{ {
gridRealityMore.Visibility = Visibility.Visible;
gridTlsMore.Visibility = Visibility.Hidden; gridTlsMore.Visibility = Visibility.Hidden;
} }
else if (security == Global.StreamSecurity)
{
gridRealityMore.Visibility = Visibility.Hidden;
gridTlsMore.Visibility = Visibility.Visible;
}
else else
{ {
gridTlsMore.Visibility = Visibility.Visible; gridRealityMore.Visibility = Visibility.Hidden;
gridTlsMore.Visibility = Visibility.Hidden;
} }
} }
private void btnGUID_Click(object sender, RoutedEventArgs e) private void btnGUID_Click(object sender, RoutedEventArgs e)
{ {
txtId.Text = txtId.Text =
@@ -184,12 +216,12 @@ namespace v2rayN.Views
return; return;
} }
if (network.Equals(Global.DefaultNetwork)) if (network == Global.DefaultNetwork)
{ {
cmbHeaderType.Items.Add(Global.None); cmbHeaderType.Items.Add(Global.None);
cmbHeaderType.Items.Add(Global.TcpHeaderHttp); cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
} }
else if (network.Equals("kcp") || network.Equals("quic")) else if (network is "kcp" or "quic")
{ {
cmbHeaderType.Items.Add(Global.None); cmbHeaderType.Items.Add(Global.None);
Global.kcpHeaderTypes.ForEach(it => Global.kcpHeaderTypes.ForEach(it =>
@@ -197,7 +229,7 @@ namespace v2rayN.Views
cmbHeaderType.Items.Add(it); cmbHeaderType.Items.Add(it);
}); });
} }
else if (network.Equals("grpc")) else if (network == "grpc")
{ {
cmbHeaderType.Items.Add(Global.GrpcgunMode); cmbHeaderType.Items.Add(Global.GrpcgunMode);
cmbHeaderType.Items.Add(Global.GrpcmultiMode); cmbHeaderType.Items.Add(Global.GrpcmultiMode);
@@ -221,37 +253,39 @@ namespace v2rayN.Views
tipPath.Text = tipPath.Text =
tipHeaderType.Text = string.Empty; tipHeaderType.Text = string.Empty;
if (network.Equals(Global.DefaultNetwork)) switch (network)
{ {
tipRequestHost.Text = ResUI.TransportRequestHostTip1; case Global.DefaultNetwork:
tipHeaderType.Text = ResUI.TransportHeaderTypeTip1; tipRequestHost.Text = ResUI.TransportRequestHostTip1;
} tipHeaderType.Text = ResUI.TransportHeaderTypeTip1;
else if (network.Equals("kcp")) break;
{
tipHeaderType.Text = ResUI.TransportHeaderTypeTip2; case "kcp":
tipPath.Text = ResUI.TransportPathTip5; tipHeaderType.Text = ResUI.TransportHeaderTypeTip2;
} tipPath.Text = ResUI.TransportPathTip5;
else if (network.Equals("ws")) break;
{
tipRequestHost.Text = ResUI.TransportRequestHostTip2; case "ws":
tipPath.Text = ResUI.TransportPathTip1; tipRequestHost.Text = ResUI.TransportRequestHostTip2;
} tipPath.Text = ResUI.TransportPathTip1;
else if (network.Equals("h2")) break;
{
tipRequestHost.Text = ResUI.TransportRequestHostTip3; case "h2":
tipPath.Text = ResUI.TransportPathTip2; tipRequestHost.Text = ResUI.TransportRequestHostTip3;
} tipPath.Text = ResUI.TransportPathTip2;
else if (network.Equals("quic")) break;
{
tipRequestHost.Text = ResUI.TransportRequestHostTip4; case "quic":
tipPath.Text = ResUI.TransportPathTip3; tipRequestHost.Text = ResUI.TransportRequestHostTip4;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip3; tipPath.Text = ResUI.TransportPathTip3;
} tipHeaderType.Text = ResUI.TransportHeaderTypeTip3;
else if (network.Equals("grpc")) break;
{
tipPath.Text = ResUI.TransportPathTip4; case "grpc":
tipHeaderType.Text = ResUI.TransportHeaderTypeTip4; tipPath.Text = ResUI.TransportPathTip4;
labHeaderType.Visibility = Visibility.Hidden; tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
labHeaderType.Visibility = Visibility.Hidden;
break;
} }
} }
@@ -259,6 +293,5 @@ namespace v2rayN.Views
{ {
this.Close(); this.Close();
} }
} }
} }

View File

@@ -18,6 +18,7 @@
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
KeyDown="GlobalHotkeySettingWindow_KeyDown" KeyDown="GlobalHotkeySettingWindow_KeyDown"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
@@ -71,7 +72,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -88,7 +89,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -105,7 +106,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
@@ -121,7 +122,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
@@ -137,7 +138,7 @@
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
IsReadOnly="True" IsReadOnly="True"
Style="{StaticResource MaterialDesignOutlinedTextBox}" /> Style="{StaticResource MyOutlinedTextBox}" />
</Grid> </Grid>
<TextBlock <TextBlock
@@ -149,7 +150,7 @@
<Grid <Grid
Grid.Row="2" Grid.Row="2"
Margin="16" Margin="8"
HorizontalAlignment="Center"> HorizontalAlignment="Center">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="150" /> <ColumnDefinition Width="150" />
@@ -180,4 +181,4 @@
</Grid> </Grid>
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</reactiveui:ReactiveWindow> </reactiveui:ReactiveWindow>

View File

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

View File

@@ -10,13 +10,13 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net" xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:v2rayN.Resx" 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" xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="v2rayN" Title="v2rayN"
Width="900" Width="900"
Height="700" Height="700"
MinWidth="800" MinWidth="900"
MinHeight="600" MinHeight="700"
x:TypeArguments="vms:MainWindowViewModel" x:TypeArguments="vms:MainWindowViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
@@ -53,7 +53,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Server" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Server" />
<TextBlock Text="{x:Static resx:ResUI.menuServers}" /> <TextBlock Text="{x:Static resx:ResUI.menuServers}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -91,7 +94,6 @@
x:Name="menuAddServerViaScan" x:Name="menuAddServerViaScan"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddServerViaScan}" /> Header="{x:Static resx:ResUI.menuAddServerViaScan}" />
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
@@ -99,7 +101,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="BookClockOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="BookClockOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuSubscription}" /> <TextBlock Text="{x:Static resx:ResUI.menuSubscription}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -131,7 +136,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="SettingsOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="SettingsOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuSetting}" /> <TextBlock Text="{x:Static resx:ResUI.menuSetting}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -148,6 +156,10 @@
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGlobalHotkeySetting}" /> Header="{x:Static resx:ResUI.menuGlobalHotkeySetting}" />
<Separator Margin="-40,5" /> <Separator Margin="-40,5" />
<MenuItem
x:Name="menuRebootAsAdmin"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRebootAsAdmin}" />
<MenuItem <MenuItem
x:Name="menuSettingsSetUWP" x:Name="menuSettingsSetUWP"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -169,7 +181,10 @@
<MenuItem x:Name="menuReload" Padding="8,0"> <MenuItem x:Name="menuReload" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Reload" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Reload" />
<TextBlock Text="{x:Static resx:ResUI.menuReload}" /> <TextBlock Text="{x:Static resx:ResUI.menuReload}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -180,7 +195,10 @@
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Update" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Update" />
<TextBlock Text="{x:Static resx:ResUI.menuCheckUpdate}" /> <TextBlock Text="{x:Static resx:ResUI.menuCheckUpdate}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -210,6 +228,11 @@
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="Clash.Meta Core" /> Header="Clash.Meta Core" />
<Separator Margin="-40,5" /> <Separator Margin="-40,5" />
<MenuItem
x:Name="menuCheckUpdateSingBoxCore"
Height="{StaticResource MenuItemHeight}"
Header="SingBox Core" />
<Separator Margin="-40,5" />
<MenuItem <MenuItem
x:Name="menuCheckUpdateGeo" x:Name="menuCheckUpdateGeo"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -221,7 +244,10 @@
<MenuItem x:Name="menuHelp" Padding="8,0"> <MenuItem x:Name="menuHelp" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="HelpCircleOutline" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="HelpCircleOutline" />
<TextBlock Text="{x:Static resx:ResUI.menuHelp}" /> <TextBlock Text="{x:Static resx:ResUI.menuHelp}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -235,7 +261,10 @@
Click="menuPromotion_Click"> Click="menuPromotion_Click">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="VolumeHigh" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="VolumeHigh" />
<TextBlock Text="{x:Static resx:ResUI.menuPromotion}" /> <TextBlock Text="{x:Static resx:ResUI.menuPromotion}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -249,7 +278,10 @@
Click="menuClose_Click"> Click="menuClose_Click">
<MenuItem.Header> <MenuItem.Header>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0,0,8,0" Kind="Minimize" /> <materialDesign:PackIcon
Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Minimize" />
<TextBlock Text="{x:Static resx:ResUI.menuClose}" /> <TextBlock Text="{x:Static resx:ResUI.menuClose}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -259,73 +291,117 @@
<materialDesign:PopupBox <materialDesign:PopupBox
Padding="8,0" Padding="8,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}"> Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
<StackPanel Margin="8"> <StackPanel Margin="8">
<StackPanel Orientation="Horizontal"> <Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsColorMode}" /> Text="{x:Static resx:ResUI.TbSettingsColorMode}" />
<ToggleButton x:Name="togDarkMode" Margin="8" /> <ToggleButton
</StackPanel> x:Name="togDarkMode"
<StackPanel Orientation="Horizontal"> Grid.Row="0"
Grid.Column="1"
Margin="8" />
<TextBlock <TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsColor}" /> Text="{x:Static resx:ResUI.TbSettingsColor}" />
<ComboBox <ComboBox
x:Name="cmbSwatches" x:Name="cmbSwatches"
Grid.Row="1"
Grid.Column="1"
Width="100" Width="100"
Margin="8" Margin="8"
DisplayMemberPath="Name" DisplayMemberPath="Name"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock <TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsFontSize}" />
<ComboBox
x:Name="cmbCurrentFontSize"
Grid.Row="2"
Grid.Column="1"
Width="100"
Margin="8"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLanguage}" /> Text="{x:Static resx:ResUI.TbSettingsLanguage}" />
<ComboBox <ComboBox
x:Name="cmbCurrentLanguage" x:Name="cmbCurrentLanguage"
Grid.Row="3"
Grid.Column="1"
Width="100" Width="100"
Margin="8" Margin="8"
materialDesign:HintAssist.Hint="Language" materialDesign:HintAssist.Hint="Language"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</StackPanel> </Grid>
</StackPanel> </StackPanel>
</materialDesign:PopupBox> </materialDesign:PopupBox>
</ToolBar> </ToolBar>
</ToolBarTray> </ToolBarTray>
<ToolBarTray DockPanel.Dock="Top"> <WrapPanel Margin="2" DockPanel.Dock="Top">
<ToolBar <ListBox
HorizontalAlignment="Center" x:Name="lstGroup"
VerticalAlignment="Center" FontSize="{DynamicResource StdFontSize}"
ClipToBounds="True" ItemContainerStyle="{StaticResource MyChipListBoxItem}"
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
<ListBox x:Name="lstGroup" Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}"> <ListBox.ItemTemplate>
<ListBox.ItemTemplate> <DataTemplate>
<DataTemplate> <TextBlock Text="{Binding remarks}" />
<TextBlock Text="{Binding remarks}" /> </DataTemplate>
</DataTemplate> </ListBox.ItemTemplate>
</ListBox.ItemTemplate> </ListBox>
</ListBox> <Button
<Button x:Name="btnAddSub"
x:Name="btnAddSub" Width="30"
Width="30" Height="30"
Height="30" Margin="4,0"
Margin="8,0" Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"> <materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
<materialDesign:PackIcon Kind="Plus" /> </Button>
</Button> <Button
<Separator /> x:Name="btnAutofitColumnWidth"
<TextBox Width="30"
x:Name="txtServerFilter" Height="30"
Width="200" Margin="4,0"
Margin="8,0" Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}">
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}" <materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
materialDesign:TextFieldAssist.HasClearButton="True" /> </Button>
</ToolBar> <TextBox
</ToolBarTray> x:Name="txtServerFilter"
Width="200"
Margin="4,0"
VerticalContentAlignment="Center"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
materialDesign:TextFieldAssist.HasClearButton="True"
Style="{StaticResource DefTextBox}" />
</WrapPanel>
<materialDesign:ColorZone <materialDesign:ColorZone
Height="50" Height="50"
@@ -374,6 +450,7 @@
Width="120" Width="120"
Margin="8,0" Margin="8,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSystemproxy}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSystemproxy}"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFloatingHintComboBox}"> Style="{StaticResource MaterialDesignFloatingHintComboBox}">
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" /> <ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" /> <ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
@@ -387,6 +464,7 @@
Margin="8,0" Margin="8,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
DisplayMemberPath="remarks" DisplayMemberPath="remarks"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFloatingHintComboBox}" /> Style="{StaticResource MaterialDesignFloatingHintComboBox}" />
</StackPanel> </StackPanel>
@@ -424,6 +502,7 @@
GridLinesVisibility="All" GridLinesVisibility="All"
HeadersVisibility="All" HeadersVisibility="All"
IsReadOnly="True" IsReadOnly="True"
RowHeaderWidth="40"
Style="{StaticResource DefDataGrid}"> Style="{StaticResource DefDataGrid}">
<DataGrid.InputBindings> <DataGrid.InputBindings>
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" /> <KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" />
@@ -495,27 +574,30 @@
Width="200" Width="200"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
DisplayMemberPath="remarks" DisplayMemberPath="remarks"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilledComboBox}" /> Style="{StaticResource MaterialDesignFilledComboBox}" />
</DockPanel> </DockPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem <MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
x:Name="menuMoveTop" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveTop"
Header="{x:Static resx:ResUI.menuMoveTop}" /> Height="{StaticResource MenuItemHeight}"
<MenuItem Header="{x:Static resx:ResUI.menuMoveTop}" />
x:Name="menuMoveUp" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveUp"
Header="{x:Static resx:ResUI.menuMoveUp}" /> Height="{StaticResource MenuItemHeight}"
<MenuItem Header="{x:Static resx:ResUI.menuMoveUp}" />
x:Name="menuMoveDown" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveDown"
Header="{x:Static resx:ResUI.menuMoveDown}" /> Height="{StaticResource MenuItemHeight}"
<MenuItem Header="{x:Static resx:ResUI.menuMoveDown}" />
x:Name="menuMoveBottom" <MenuItem
Height="{StaticResource MenuItemHeight}" x:Name="menuMoveBottom"
Header="{x:Static resx:ResUI.menuMoveBottom}" /> Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}" />
</MenuItem>
<MenuItem <MenuItem
x:Name="menuSelectAll" x:Name="menuSelectAll"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -543,60 +625,67 @@
<DataGrid.Resources> <DataGrid.Resources>
<Style BasedOn="{StaticResource MaterialDesignDataGridRow}" TargetType="DataGridRow"> <Style BasedOn="{StaticResource MaterialDesignDataGridRow}" TargetType="DataGridRow">
<EventSetter Event="MouseDoubleClick" Handler="LstProfiles_MouseDoubleClick" /> <EventSetter Event="MouseDoubleClick" Handler="LstProfiles_MouseDoubleClick" />
</Style> </Style>
<Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader"> <Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
<EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" /> <EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" />
</Style> </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.Resources>
<DataGrid.Columns> <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" Width="80"
Binding="{Binding configType}" Binding="{Binding configType}"
ExName="configType"
Header="{x:Static resx:ResUI.LvServiceType}" /> Header="{x:Static resx:ResUI.LvServiceType}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="150" Width="150"
Binding="{Binding remarks}" Binding="{Binding remarks}"
Header="{x:Static resx:ResUI.LvAlias}" /> ExName="remarks"
<DataGridTextColumn Header="{x:Static resx:ResUI.LvRemarks}" />
<base:MyDGTextColumn
Width="120" Width="120"
Binding="{Binding address}" Binding="{Binding address}"
ExName="address"
Header="{x:Static resx:ResUI.LvAddress}" /> Header="{x:Static resx:ResUI.LvAddress}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="60" Width="60"
Binding="{Binding port}" Binding="{Binding port}"
ExName="port"
Header="{x:Static resx:ResUI.LvPort}" /> Header="{x:Static resx:ResUI.LvPort}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding security}" Binding="{Binding security}"
ExName="security"
Header="{x:Static resx:ResUI.LvEncryptionMethod}" /> Header="{x:Static resx:ResUI.LvEncryptionMethod}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding network}" Binding="{Binding network}"
ExName="network"
Header="{x:Static resx:ResUI.LvTransportProtocol}" /> Header="{x:Static resx:ResUI.LvTransportProtocol}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding streamSecurity}" Binding="{Binding streamSecurity}"
ExName="streamSecurity"
Header="{x:Static resx:ResUI.LvTLS}" /> Header="{x:Static resx:ResUI.LvTLS}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding subRemarks}" Binding="{Binding subRemarks}"
ExName="subRemarks"
Header="{x:Static resx:ResUI.LvSubscription}" /> Header="{x:Static resx:ResUI.LvSubscription}" />
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding delayVal}" Binding="{Binding delayVal}"
ExName="delayVal"
Header="{x:Static resx:ResUI.LvTestDelay}"> Header="{x:Static resx:ResUI.LvTestDelay}">
<DataGridTextColumn.ElementStyle> <DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"> <Style TargetType="{x:Type TextBlock}">
@@ -604,45 +693,48 @@
<Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" /> <Setter Property="Foreground" Value="{Binding delay, Converter={StaticResource DelayColorConverter}}" />
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </base:MyDGTextColumn>
<DataGridTextColumn <base:MyDGTextColumn
Width="100" Width="100"
Binding="{Binding speedVal}" Binding="{Binding speedVal}"
ExName="speedVal"
Header="{x:Static resx:ResUI.LvTestSpeed}"> Header="{x:Static resx:ResUI.LvTestSpeed}">
<DataGridTextColumn.ElementStyle> <DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"> <Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" /> <Setter Property="HorizontalAlignment" Value="Right" />
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </base:MyDGTextColumn>
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTodayUp" x:Name="colTodayUp"
Width="100" Width="100"
Binding="{Binding todayUp}" Binding="{Binding todayUp}"
ExName="todayUp"
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" /> Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTodayDown" x:Name="colTodayDown"
Width="100" Width="100"
Binding="{Binding todayDown}" Binding="{Binding todayDown}"
ExName="todayDown"
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" /> Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTotalUp" x:Name="colTotalUp"
Width="100" Width="100"
Binding="{Binding totalUp}" Binding="{Binding totalUp}"
ExName="totalUp"
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" /> Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
<DataGridTextColumn <base:MyDGTextColumn
x:Name="colTotalDown" x:Name="colTotalDown"
Width="100" Width="100"
Binding="{Binding totalDown}" Binding="{Binding totalDown}"
ExName="totalDown"
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" /> Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" /> <GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" />
<local:MsgView Grid.Row="2" /> <local:MsgView Grid.Row="2" />
</Grid> </Grid>
</DockPanel> </DockPanel>
<tb:TaskbarIcon <tb:TaskbarIcon
x:Name="tbNotify" x:Name="tbNotify"
@@ -656,6 +748,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyClear2" x:Name="menuSystemProxyClear2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyClear}" />
</StackPanel> </StackPanel>
@@ -667,6 +760,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxySet2" x:Name="menuSystemProxySet2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxySet}" />
</StackPanel> </StackPanel>
@@ -678,6 +772,7 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyNothing2" x:Name="menuSystemProxyNothing2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyNothing}" />
</StackPanel> </StackPanel>
@@ -689,12 +784,13 @@
<materialDesign:PackIcon <materialDesign:PackIcon
x:Name="menuSystemProxyPac2" x:Name="menuSystemProxyPac2"
Margin="0,0,8,0" Margin="0,0,8,0"
VerticalAlignment="Center"
Kind="Check" /> Kind="Check" />
<TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" /> <TextBlock Text="{x:Static resx:ResUI.menuSystemProxyPac}" />
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
<Separator /> <Separator x:Name="sepRoutings" />
<MenuItem x:Name="menuRoutings" Height="Auto"> <MenuItem x:Name="menuRoutings" Height="Auto">
<MenuItem.Header> <MenuItem.Header>
<DockPanel> <DockPanel>
@@ -703,6 +799,7 @@
MaxWidth="300" MaxWidth="300"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
DisplayMemberPath="remarks" DisplayMemberPath="remarks"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilledComboBox}" /> Style="{StaticResource MaterialDesignFilledComboBox}" />
</DockPanel> </DockPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -715,6 +812,7 @@
MaxWidth="300" MaxWidth="300"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}"
DisplayMemberPath="Text" DisplayMemberPath="Text"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilledComboBox}" /> Style="{StaticResource MaterialDesignFilledComboBox}" />
</DockPanel> </DockPanel>
</MenuItem.Header> </MenuItem.Header>
@@ -744,9 +842,25 @@
Header="{x:Static resx:ResUI.menuExit}" /> Header="{x:Static resx:ResUI.menuExit}" />
</ContextMenu> </ContextMenu>
</tb:TaskbarIcon.ContextMenu> </tb:TaskbarIcon.ContextMenu>
<tb:TaskbarIcon.TrayToolTip>
<Border
x:Name="borTrayToolTip"
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> </tb:TaskbarIcon>
<materialDesign:Snackbar x:Name="MainSnackbar" MessageQueue="{materialDesign:MessageQueue}" /> <materialDesign:Snackbar x:Name="MainSnackbar" MessageQueue="{materialDesign:MessageQueue}" />
</Grid> </Grid>
</materialDesign:DialogHost> </materialDesign:DialogHost>
</reactiveui:ReactiveWindow> </reactiveui:ReactiveWindow>

View File

@@ -1,7 +1,6 @@
using ReactiveUI; using ReactiveUI;
using Splat; using Splat;
using System.ComponentModel; using System.ComponentModel;
using System.Drawing;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@@ -9,12 +8,12 @@ using System.Windows.Controls.Primitives;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using v2rayN.Base;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Mode; using v2rayN.Mode;
using v2rayN.Resx; using v2rayN.Resx;
using v2rayN.ViewModels; using v2rayN.ViewModels;
using Point = System.Windows.Point; using Point = System.Windows.Point;
using SystemInformation = System.Windows.Forms.SystemInformation;
namespace v2rayN.Views namespace v2rayN.Views
{ {
@@ -30,6 +29,8 @@ namespace v2rayN.Views
App.Current.SessionEnding += Current_SessionEnding; App.Current.SessionEnding += Current_SessionEnding;
this.Closing += MainWindow_Closing; this.Closing += MainWindow_Closing;
this.PreviewKeyDown += MainWindow_PreviewKeyDown; this.PreviewKeyDown += MainWindow_PreviewKeyDown;
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown; lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged; lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
lstProfiles.LoadingRow += LstProfiles_LoadingRow; lstProfiles.LoadingRow += LstProfiles_LoadingRow;
@@ -45,6 +46,11 @@ namespace v2rayN.Views
ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler); ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++)
{
cmbCurrentFontSize.Items.Add(i.ToString());
}
Global.Languages.ForEach(it => Global.Languages.ForEach(it =>
{ {
cmbCurrentLanguage.Items.Add(it); cmbCurrentLanguage.Items.Add(it);
@@ -87,7 +93,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
//servers ping //servers ping
this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.PingServerCmd, v => v.menuPingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.PingServerCmd, v => v.menuPingServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables);
@@ -112,6 +118,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.OptionSettingCmd, v => v.menuOptionSetting).DisposeWith(disposables); 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.RoutingSettingCmd, v => v.menuRoutingSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.GlobalHotkeySettingCmd, v => v.menuGlobalHotkeySetting).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.ClearServerStatisticsCmd, v => v.menuClearServerStatistics).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportOldGuiConfigCmd, v => v.menuImportOldGuiConfig).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportOldGuiConfigCmd, v => v.menuImportOldGuiConfig).DisposeWith(disposables);
@@ -122,6 +129,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.CheckUpdateXrayCoreCmd, v => v.menuCheckUpdateXrayCore).DisposeWith(disposables); 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.CheckUpdateClashCoreCmd, v => v.menuCheckUpdateClashCore).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateClashMetaCoreCmd, v => v.menuCheckUpdateClashMetaCore).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.CheckUpdateGeoCmd, v => v.menuCheckUpdateGeo).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
@@ -141,9 +149,11 @@ namespace v2rayN.Views
this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables); 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.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.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.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).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 //tray menu
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables);
@@ -152,8 +162,10 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.BlShowTrayTip, v => v.borTrayToolTip.Visibility).DisposeWith(disposables);
//status bar //status bar
this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables);
@@ -173,6 +185,7 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables);
}); });
@@ -183,23 +196,30 @@ namespace v2rayN.Views
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed; spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed;
//if (_config.uiItem.autoHideStartup)
//{
// WindowState = WindowState.Minimized;
//}
if (!_config.guiItem.enableHWA)
{
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
}
} }
#region Event #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) AutofitColumnWidth();
{ });
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}));
} }
else if (action == "ProfilesFocus") else if (action == EViewAction.ProfilesFocus)
{ {
lstProfiles.Focus(); lstProfiles.Focus();
} }
@@ -229,6 +249,7 @@ namespace v2rayN.Views
{ {
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList(); ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
} }
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e) private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
{ {
//if (e.Row.GetIndex() == 0) //if (e.Row.GetIndex() == 0)
@@ -259,24 +280,8 @@ namespace v2rayN.Views
return; return;
} }
//find index var colName = ((MyDGTextColumn)colHeader.Column).ExName;
var index = lstProfiles.Columns.IndexOf(colHeader.Column); ViewModel?.SortServer(colName);
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);
} }
private void menuSelectAll_Click(object sender, RoutedEventArgs e) private void menuSelectAll_Click(object sender, RoutedEventArgs e)
@@ -349,7 +354,7 @@ namespace v2rayN.Views
} }
else else
{ {
if (e.Key == Key.Enter || e.Key == Key.Return) if (e.Key is Key.Enter or Key.Return)
{ {
ViewModel?.SetDefaultServer(); ViewModel?.SetDefaultServer();
} }
@@ -376,12 +381,12 @@ namespace v2rayN.Views
} }
} }
private void menuClose_Click(object sender, RoutedEventArgs e) private void menuClose_Click(object sender, RoutedEventArgs e)
{ {
StorageUI(); StorageUI();
ViewModel?.ShowHideWindow(false); ViewModel?.ShowHideWindow(false);
} }
private void menuPromotion_Click(object sender, RoutedEventArgs e) private void menuPromotion_Click(object sender, RoutedEventArgs e)
{ {
Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}"); Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
@@ -391,11 +396,34 @@ namespace v2rayN.Views
{ {
ViewModel?.TestServerAvailability(); ViewModel?.TestServerAvailability();
} }
private void menuSettingsSetUWP_Click(object sender, RoutedEventArgs e) private void menuSettingsSetUWP_Click(object sender, RoutedEventArgs e)
{ {
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
} }
#endregion
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 Event
#region UI #region UI
@@ -407,28 +435,39 @@ namespace v2rayN.Views
Height = _config.uiItem.mainHeight; Height = _config.uiItem.mainHeight;
} }
IntPtr hWnd = new WindowInteropHelper(this).EnsureHandle(); var maxWidth = SystemParameters.WorkArea.Width;
Graphics g = Graphics.FromHwnd(hWnd); var maxHeight = SystemParameters.WorkArea.Height;
if (Width > SystemInformation.WorkingArea.Width * 96 / g.DpiX) if (Width > maxWidth) Width = maxWidth;
{ if (Height > maxHeight) Height = maxHeight;
Width = SystemInformation.WorkingArea.Width * 96 / g.DpiX;
}
if (Height > SystemInformation.WorkingArea.Height * 96 / g.DpiY)
{
Height = SystemInformation.WorkingArea.Height * 96 / g.DpiY;
}
if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0) if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0)
{ {
gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star); gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star); gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
} }
for (int k = 0; k < lstProfiles.Columns.Count; k++) var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList();
for (int i = 0; i < lvColumnItem.Count; i++)
{ {
var width = ConfigHandler.GetformMainLvColWidth(ref _config, ((EServerColName)k).ToString(), Convert.ToInt32(lstProfiles.Columns[k].Width.Value)); var item = lvColumnItem[i];
lstProfiles.Columns[k].Width = width; for (int k = 1; k < lstProfiles.Columns.Count; k++)
{
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
if (item2.ExName == item.Name)
{
if (item.Width < 0)
{
item2.Visibility = Visibility.Hidden;
}
else
{
item2.Width = item.Width;
item2.DisplayIndex = i;
}
}
}
} }
if (!_config.enableStatistics)
if (!_config.guiItem.enableStatistics)
{ {
colTodayUp.Visibility = Visibility.Hidden; colTodayUp.Visibility = Visibility.Hidden;
colTodayDown.Visibility = Visibility.Hidden; colTodayDown.Visibility = Visibility.Hidden;
@@ -436,15 +475,25 @@ namespace v2rayN.Views
colTotalDown.Visibility = Visibility.Hidden; colTotalDown.Visibility = Visibility.Hidden;
} }
} }
private void StorageUI() private void StorageUI()
{ {
_config.uiItem.mainWidth = this.Width; _config.uiItem.mainWidth = this.Width;
_config.uiItem.mainHeight = this.Height; _config.uiItem.mainHeight = this.Height;
List<ColumnItem> lvColumnItem = new();
for (int k = 0; k < lstProfiles.Columns.Count; k++) 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.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1);
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1); _config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1);
} }
@@ -463,20 +512,20 @@ namespace v2rayN.Views
menuHelp.Items.Add(item); menuHelp.Items.Add(item);
} }
} }
private void MenuItem_Click(object sender, RoutedEventArgs e) private void MenuItem_Click(object sender, RoutedEventArgs e)
{ {
if (sender is MenuItem) if (sender is MenuItem item)
{ {
MenuItem item = (MenuItem)sender;
Utils.ProcessStart(item.Tag.ToString()); Utils.ProcessStart(item.Tag.ToString());
} }
} }
#endregion UI
#endregion
#region Drag and Drop #region Drag and Drop
private Point startPoint = new Point(); private Point startPoint = new();
private int startIndex = -1; private int startIndex = -1;
private string formatData = "ProfileItemModel"; private string formatData = "ProfileItemModel";
@@ -500,12 +549,12 @@ namespace v2rayN.Views
return null; return null;
} }
private void LstProfiles_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) private void LstProfiles_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ {
// Get current mouse position // Get current mouse position
startPoint = e.GetPosition(null); startPoint = e.GetPosition(null);
} }
private void LstProfiles_MouseMove(object sender, MouseEventArgs e) private void LstProfiles_MouseMove(object sender, MouseEventArgs e)
{ {
// Get the current mouse position // Get the current mouse position
@@ -517,8 +566,7 @@ namespace v2rayN.Views
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{ {
// Get the dragged Item // Get the dragged Item
var listView = sender as DataGrid; if (sender is not DataGrid listView) return;
if (listView == null) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource); var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null) return; // Abort if (listViewItem == null) return; // Abort
// Find the data behind the ListViewItem // Find the data behind the ListViewItem
@@ -526,7 +574,7 @@ namespace v2rayN.Views
if (item == null) return; // Abort if (item == null) return; // Abort
// Initialize the drag & drop operation // Initialize the drag & drop operation
startIndex = lstProfiles.SelectedIndex; startIndex = lstProfiles.SelectedIndex;
DataObject dragData = new DataObject(formatData, item); DataObject dragData = new(formatData, item);
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move); DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
} }
} }
@@ -544,8 +592,7 @@ namespace v2rayN.Views
if (e.Data.GetDataPresent(formatData) && sender == e.Source) if (e.Data.GetDataPresent(formatData) && sender == e.Source)
{ {
// Get the drop Item destination // Get the drop Item destination
var listView = sender as DataGrid; if (sender is not DataGrid listView) return;
if (listView == null) return;
var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource); var listViewItem = FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);
if (listViewItem == null) if (listViewItem == null)
{ {
@@ -556,7 +603,7 @@ namespace v2rayN.Views
// Find the data behind the Item // Find the data behind the Item
ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem); ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
if (item == null) return; if (item == null) return;
// Move item into observable collection // Move item into observable collection
// (this will be automatically reflected to lstView.ItemsSource) // (this will be automatically reflected to lstView.ItemsSource)
e.Effects = DragDropEffects.Move; e.Effects = DragDropEffects.Move;
@@ -566,8 +613,6 @@ namespace v2rayN.Views
} }
} }
#endregion #endregion Drag and Drop
} }
} }

View File

@@ -20,6 +20,7 @@
Margin="8,0" Margin="8,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryHueLightBrush}" Foreground="{DynamicResource PrimaryHueLightBrush}"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.MsgInformationTitle}" /> Text="{x:Static resx:ResUI.MsgInformationTitle}" />
<ComboBox <ComboBox
x:Name="cmbMsgFilter" x:Name="cmbMsgFilter"
@@ -27,10 +28,13 @@
Margin="8,0" Margin="8,0"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}"
materialDesign:TextFieldAssist.HasClearButton="True" materialDesign:TextFieldAssist.HasClearButton="True"
IsEditable="True" /> IsEditable="True"
Style="{StaticResource DefComboBox}"
TextBoxBase.TextChanged="cmbMsgFilter_TextChanged" />
<TextBlock <TextBlock
Margin="8,0" Margin="8,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAutoRefresh}" /> Text="{x:Static resx:ResUI.TbAutoRefresh}" />
<ToggleButton <ToggleButton
x:Name="togAutoRefresh" x:Name="togAutoRefresh"
@@ -41,9 +45,11 @@
<TextBox <TextBox
Name="txtMsg" Name="txtMsg"
BorderThickness="0" BorderThickness="0"
FontSize="11" FontSize="{DynamicResource StdFontSizeMsg}"
HorizontalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
IsReadOnly="True" IsReadOnly="True"
IsReadOnlyCaretVisible="True"
TextAlignment="Left"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Visible"> VerticalScrollBarVisibility="Visible">
<TextBox.ContextMenu> <TextBox.ContextMenu>
@@ -68,11 +74,8 @@
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Click="menuMsgViewClear_Click" Click="menuMsgViewClear_Click"
Header="{x:Static resx:ResUI.menuMsgViewClear}" /> Header="{x:Static resx:ResUI.menuMsgViewClear}" />
</ContextMenu> </ContextMenu>
</TextBox.ContextMenu> </TextBox.ContextMenu>
</TextBox> </TextBox>
</DockPanel> </DockPanel>
</UserControl> </UserControl>

View File

@@ -3,45 +3,67 @@ using System.Reactive.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows.Threading; using System.Windows.Threading;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Mode;
namespace v2rayN.Views namespace v2rayN.Views
{ {
public partial class MsgView public partial class MsgView
{ {
private static Config _config;
private string lastMsgFilter;
private bool lastMsgFilterNotAvailable;
public MsgView() public MsgView()
{ {
InitializeComponent(); InitializeComponent();
_config = LazyConfig.Instance.GetConfig();
MessageBus.Current.Listen<string>("MsgView").Subscribe(x => DelegateAppendText(x)); MessageBus.Current.Listen<string>("MsgView").Subscribe(x => DelegateAppendText(x));
Global.PresetMsgFilters.ForEach(it => Global.PresetMsgFilters.ForEach(it =>
{ {
cmbMsgFilter.Items.Add(it); cmbMsgFilter.Items.Add(it);
}); });
if (!_config.uiItem.mainMsgFilter.IsNullOrEmpty())
{
cmbMsgFilter.Text = _config.uiItem.mainMsgFilter;
}
} }
void DelegateAppendText(string msg) private void DelegateAppendText(string msg)
{ {
Dispatcher.BeginInvoke(new Action<string>(AppendText), DispatcherPriority.Send, msg); Dispatcher.BeginInvoke(AppendText, DispatcherPriority.Send, msg);
} }
public void AppendText(string msg) public void AppendText(string msg)
{ {
if (msg.Equals(Global.CommandClearMsg)) if (msg == Global.CommandClearMsg)
{ {
ClearMsg(); ClearMsg();
return; return;
} }
if (!togAutoRefresh.IsChecked.Value) if (togAutoRefresh.IsChecked == false)
{ {
return; return;
} }
var MsgFilter = cmbMsgFilter.Text.TrimEx(); var MsgFilter = cmbMsgFilter.Text.TrimEx();
if (!Utils.IsNullOrEmpty(MsgFilter)) if (MsgFilter != lastMsgFilter) lastMsgFilterNotAvailable = false;
if (!string.IsNullOrEmpty(MsgFilter) && !lastMsgFilterNotAvailable)
{ {
if (!Regex.IsMatch(msg, MsgFilter)) try
{ {
return; if (!Regex.IsMatch(msg, MsgFilter)) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD>
{
return;
}
}
catch (Exception)
{
lastMsgFilterNotAvailable = true;
} }
} }
lastMsgFilter = MsgFilter;
ShowMsg(msg); ShowMsg(msg);
} }
@@ -88,5 +110,9 @@ namespace v2rayN.Views
ClearMsg(); ClearMsg();
} }
private void cmbMsgFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
_config.uiItem.mainMsgFilter = cmbMsgFilter.Text.TrimEx();
}
} }
} }

View File

@@ -10,19 +10,20 @@
xmlns:resx="clr-namespace:v2rayN.Resx" xmlns:resx="clr-namespace:v2rayN.Resx"
xmlns:vms="clr-namespace:v2rayN.ViewModels" xmlns:vms="clr-namespace:v2rayN.ViewModels"
Title="{x:Static resx:ResUI.menuSetting}" Title="{x:Static resx:ResUI.menuSetting}"
Width="900" Width="1000"
Height="700" Height="700"
x:TypeArguments="vms:OptionSettingViewModel" x:TypeArguments="vms:OptionSettingViewModel"
Background="{DynamicResource MaterialDesignPaper}" Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
ResizeMode="NoResize" ResizeMode="NoResize"
ShowInTaskbar="False"
TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" TextElement.FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextOptions.TextFormattingMode="Display" TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="Auto" TextOptions.TextRenderingMode="Auto"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
mc:Ignorable="d"> mc:Ignorable="d">
<DockPanel Margin="16"> <DockPanel Margin="8">
<Grid HorizontalAlignment="Center" DockPanel.Dock="Bottom"> <Grid HorizontalAlignment="Center" DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="200" /> <ColumnDefinition Width="200" />
@@ -46,7 +47,7 @@
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
</Grid> </Grid>
<TabControl> <TabControl HorizontalContentAlignment="Left">
<TabItem Header="{x:Static resx:ResUI.TbSettingsCore}"> <TabItem Header="{x:Static resx:ResUI.TbSettingsCore}">
<ScrollViewer VerticalScrollBarVisibility="Visible"> <ScrollViewer VerticalScrollBarVisibility="Visible">
<Grid Margin="{StaticResource SettingItemMargin}"> <Grid Margin="{StaticResource SettingItemMargin}">
@@ -85,7 +86,8 @@
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="0" Grid.Row="0"
Grid.Column="2" Grid.Column="2"
@@ -176,7 +178,8 @@
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
@@ -190,7 +193,8 @@
Grid.Row="7" Grid.Row="7"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="8" Grid.Row="8"
@@ -212,7 +216,7 @@
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" /> Text="{x:Static resx:ResUI.TbSettingsLogEnabledToFile}" />
<ToggleButton <ToggleButton
x:Name="toglogEnabled" x:Name="toglogEnabled"
Grid.Row="9" Grid.Row="9"
@@ -231,8 +235,10 @@
x:Name="cmbloglevel" x:Name="cmbloglevel"
Grid.Row="10" Grid.Row="10"
Grid.Column="1" Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
materialDesign:HintAssist.Hint="Level" /> materialDesign:HintAssist.Hint="Level"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="11" Grid.Row="11"
@@ -259,8 +265,10 @@
x:Name="cmbdefFingerprint" x:Name="cmbdefFingerprint"
Grid.Row="12" Grid.Row="12"
Grid.Column="1" Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
IsEditable="True" /> IsEditable="True"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="13" Grid.Row="13"
@@ -273,8 +281,10 @@
x:Name="cmbdefUserAgent" x:Name="cmbdefUserAgent"
Grid.Row="13" Grid.Row="13"
Grid.Column="1" Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
IsEditable="True" /> IsEditable="True"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="13" Grid.Row="13"
Grid.Column="3" Grid.Column="3"
@@ -296,7 +306,8 @@
<ComboBox <ComboBox
x:Name="cmbdomainStrategy4Freedom" x:Name="cmbdomainStrategy4Freedom"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
</StackPanel> </StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
@@ -320,10 +331,10 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
AcceptsReturn="True" AcceptsReturn="True"
BorderThickness="1" BorderThickness="1"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</DockPanel> </DockPanel>
</TabItem> </TabItem>
<!--<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreKcp}"> <!--<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreKcp}">
@@ -353,7 +364,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="mtu" /> Text="mtu" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpmtu" x:Name="txtKcpmtu"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
@@ -367,7 +378,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="tti" /> Text="tti" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcptti" x:Name="txtKcptti"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
@@ -381,7 +392,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="uplinkCapacity" /> Text="uplinkCapacity" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpuplinkCapacity" x:Name="txtKcpuplinkCapacity"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
@@ -395,7 +406,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="downlinkCapacity" /> Text="downlinkCapacity" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpdownlinkCapacity" x:Name="txtKcpdownlinkCapacity"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
@@ -409,7 +420,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="readBufferSize" /> Text="readBufferSize" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpreadBufferSize" x:Name="txtKcpreadBufferSize"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
@@ -423,7 +434,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="writeBufferSize" /> Text="writeBufferSize" />
<TextBox <TextBox Style="{StaticResource DefTextBox}"
x:Name="txtKcpwriteBufferSize" x:Name="txtKcpwriteBufferSize"
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
@@ -443,7 +454,6 @@
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
</Grid> </Grid>
</TabItem>--> </TabItem>-->
@@ -467,11 +477,15 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
@@ -493,7 +507,8 @@
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}" /> Text="{x:Static resx:ResUI.TbSettingsStartBootTip}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -521,7 +536,8 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@@ -647,21 +663,9 @@
Grid.Row="12" Grid.Row="12"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" />
<TextBlock
Grid.Row="13"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" HorizontalAlignment="Left"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource DefTextBox}" />
Text="{x:Static resx:ResUI.TbSettingsAutoUpdate}" />
<TextBox
x:Name="txtautoUpdateSubInterval"
Grid.Row="13"
Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}" />
<TextBlock <TextBlock
Grid.Row="14" Grid.Row="14"
@@ -675,7 +679,9 @@
Grid.Row="14" Grid.Row="14"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="15" Grid.Row="15"
@@ -688,15 +694,79 @@
x:Name="cmbcurrentFontFamily" x:Name="cmbcurrentFontFamily"
Grid.Row="15" Grid.Row="15"
Grid.Column="1" Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
MaxDropDownHeight="1000" /> MaxDropDownHeight="1000"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="15" Grid.Row="15"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource ServerItemMargin}" Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}" /> Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="16"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSpeedTestTimeout}" />
<ComboBox
x:Name="cmbSpeedTestTimeout"
Grid.Row="16"
Grid.Column="1"
Width="200"
Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="17"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSpeedTestUrl}" />
<ComboBox
x:Name="cmbSpeedTestUrl"
Grid.Row="17"
Grid.Column="1"
Width="300"
Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<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" />
<TextBlock
Grid.Row="19"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
<ComboBox
x:Name="cmbSubConvertUrl"
Grid.Row="19"
Grid.Column="1"
Width="300"
Margin="{StaticResource SettingItemMargin}"
materialDesign:HintAssist.Hint="Convert Url"
IsEditable="True"
Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@@ -713,9 +783,10 @@
<ComboBox <ComboBox
x:Name="cmbsystemProxyAdvancedProtocol" x:Name="cmbsystemProxyAdvancedProtocol"
Grid.Row="4" Grid.Row="4"
MinWidth="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
materialDesign:HintAssist.Hint="Protocol" /> materialDesign:HintAssist.Hint="Protocol"
Style="{StaticResource DefComboBox}" />
</StackPanel> </StackPanel>
<TextBlock <TextBlock
@@ -731,6 +802,7 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
AcceptsReturn="True" AcceptsReturn="True"
BorderThickness="1" BorderThickness="1"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</DockPanel> </DockPanel>
@@ -751,6 +823,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -759,7 +832,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center" VerticalAlignment="Center"
@@ -767,6 +840,20 @@
Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" /> Text="{x:Static resx:ResUI.TbSettingsTunModeShowWindow}" />
<ToggleButton <ToggleButton
x:Name="togShowWindow" x:Name="togShowWindow"
Grid.Row="0"
Grid.Column="1"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsLogEnabled}" />
<ToggleButton
x:Name="togEnabledLog"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
@@ -799,7 +886,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@@ -814,7 +902,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
@@ -827,10 +916,11 @@
x:Name="txtCustomTemplate" x:Name="txtCustomTemplate"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="600" Width="400"
Margin="{StaticResource SettingItemMargin}" Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Top" VerticalAlignment="Top"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<Button <Button
x:Name="btnBrowse" x:Name="btnBrowse"
@@ -841,21 +931,49 @@
Click="btnBrowse_Click" Click="btnBrowse_Click"
Content="{x:Static resx:ResUI.TbBrowse}" Content="{x:Static resx:ResUI.TbBrowse}"
Style="{StaticResource DefButton}" /> Style="{StaticResource DefButton}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource SettingItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsTunModeBypassMode}" />
<ToggleButton
x:Name="togBypassMode"
Grid.Row="6"
Grid.Column="1"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="6"
Grid.Column="2"
Margin="{StaticResource ServerItemMargin}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsTunModeBypassModeTip}" />
</Grid> </Grid>
<Grid Margin="{StaticResource SettingItemMargin}"> <Grid
x:Name="gridTunModeDirect"
Width="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="10" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="1*" /> <ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<GroupBox <GroupBox
Grid.Column="0" Grid.Column="0"
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectIP}" Header="{x:Static resx:ResUI.TbSettingsTunModeDirectIP}"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDirectIP" Name="txtDirectIP"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -863,10 +981,72 @@
<GroupBox <GroupBox
Grid.Column="2" Grid.Column="2"
Header="{x:Static resx:ResUI.TbSettingsTunModeDirectProcess}" Header="{x:Static resx:ResUI.TbSettingsTunModeDirectProcess}"
Style="{StaticResource MaterialDesignGroupBox}"> Style="{StaticResource MyGroupBox}">
<TextBox <TextBox
Name="txtDirectProcess" Name="txtDirectProcess"
AcceptsReturn="True" AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
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="800"
Margin="{StaticResource SettingItemMargin}"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
Header="{x:Static resx:ResUI.TbSettingsTunModeProxyIP}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyIP"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="2"
Header="{x:Static resx:ResUI.TbSettingsTunModeProxyProcess}"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyProcess"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
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" TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" /> VerticalScrollBarVisibility="Auto" />
</GroupBox> </GroupBox>
@@ -901,7 +1081,8 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@@ -915,7 +1096,8 @@
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -929,7 +1111,8 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@@ -943,7 +1126,8 @@
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
@@ -957,7 +1141,8 @@
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="6"
@@ -971,9 +1156,10 @@
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource SettingItemMargin}" /> Margin="{StaticResource SettingItemMargin}"
Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
</TabItem> </TabItem>
</TabControl> </TabControl>
</DockPanel> </DockPanel>
</reactiveui:ReactiveWindow> </reactiveui:ReactiveWindow>

View File

@@ -1,4 +1,5 @@
using ReactiveUI; using Microsoft.Win32;
using ReactiveUI;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Reactive.Disposables; using System.Reactive.Disposables;
@@ -17,6 +18,7 @@ namespace v2rayN.Views
public OptionSettingWindow() public OptionSettingWindow()
{ {
InitializeComponent(); InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
ViewModel = new OptionSettingViewModel(this); ViewModel = new OptionSettingViewModel(this);
@@ -63,26 +65,52 @@ namespace v2rayN.Views
cmbCoreType6.Items.Add(it); cmbCoreType6.Items.Add(it);
}); });
for (int i = 2; i <= 6; i++)
{
cmbSpeedTestTimeout.Items.Add(i * 5);
}
Global.SpeedTestUrls.ForEach(it =>
{
cmbSpeedTestUrl.Items.Add(it);
});
Global.SubConvertUrls.ForEach(it =>
{
cmbSubConvertUrl.Items.Add(it);
});
//fill fonts //fill fonts
try try
{ {
var dir = new DirectoryInfo(Utils.GetPath(@"Resources\Fonts")); var files = Directory.GetFiles(Utils.GetFontsPath(), "*.ttf");
var files = dir.GetFiles("*.ttf"); var culture = _config.uiItem.currentLanguage == Global.Languages[0] ? "zh-cn" : "en-us";
var culture = _config.uiItem.currentLanguage.Equals(Global.Languages[0]) ? "zh-cn" : "en-us"; var culture2 = "en-us";
foreach (var it in files) foreach (var ttf in files)
{ {
var glyphTypeface = new GlyphTypeface(new Uri(Utils.GetPath(@$"Resources\Fonts\{it.Name}"))); var families = Fonts.GetFontFamilies(Utils.GetFontsPath(ttf));
var fontFace = glyphTypeface.Win32FaceNames[new CultureInfo("en-us")]; foreach (FontFamily family in families)
if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal"))
{ {
continue; var typefaces = family.GetTypefaces();
foreach (Typeface typeface in typefaces)
{
typeface.TryGetGlyphTypeface(out GlyphTypeface glyph);
//var fontFace = glyph.Win32FaceNames[new CultureInfo("en-us")];
//if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal"))
//{
// continue;
//}
var fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture)];
if (Utils.IsNullOrEmpty(fontFamily))
{
fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture2)];
if (Utils.IsNullOrEmpty(fontFamily))
{
continue;
}
}
cmbcurrentFontFamily.Items.Add(fontFamily);
break;
}
} }
var fontFamily = glyphTypeface.Win32FamilyNames[new CultureInfo(culture)];
if (Utils.IsNullOrEmpty(fontFamily))
{
continue;
}
cmbcurrentFontFamily.Items.Add(fontFamily);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -110,11 +138,9 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.defFingerprint, v => v.cmbdefFingerprint.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.defFingerprint, v => v.cmbdefFingerprint.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.defUserAgent, v => v.cmbdefUserAgent.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.defUserAgent, v => v.cmbdefUserAgent.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.remoteDNS, v => v.txtremoteDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.remoteDNS, v => v.txtremoteDNS.Text).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.Kcptti, v => v.txtKcptti.Text).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.Kcptti, v => v.txtKcptti.Text).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.KcpuplinkCapacity, v => v.txtKcpuplinkCapacity.Text).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.KcpuplinkCapacity, v => v.txtKcpuplinkCapacity.Text).DisposeWith(disposables);
@@ -123,7 +149,6 @@ namespace v2rayN.Views
//this.Bind(ViewModel, vm => vm.KcpwriteBufferSize, v => v.txtKcpwriteBufferSize.Text).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.KcpwriteBufferSize, v => v.txtKcpwriteBufferSize.Text).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.Kcpcongestion, v => v.togKcpcongestion.IsChecked).DisposeWith(disposables); //this.Bind(ViewModel, vm => vm.Kcpcongestion, v => v.togKcpcongestion.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.StatisticsFreshRate, v => v.cmbStatisticsFreshRate.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.StatisticsFreshRate, v => v.cmbStatisticsFreshRate.Text).DisposeWith(disposables);
@@ -136,23 +161,31 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.EnableDragDropSort, v => v.togEnableDragDropSort.IsChecked).DisposeWith(disposables); 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.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.autoUpdateInterval, v => v.txtautoUpdateInterval.Text).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.trayMenuServersLimit, v => v.txttrayMenuServersLimit.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.currentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.currentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableHWA, v => v.togEnableHWA.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyExceptions, v => v.txtsystemProxyExceptions.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.systemProxyExceptions, v => v.txtsystemProxyExceptions.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunShowWindow, v => v.togShowWindow.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunShowWindow, v => v.togShowWindow.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnabledLog, v => v.togEnabledLog.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunCustomTemplate, v => v.txtCustomTemplate.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunCustomTemplate, v => v.txtCustomTemplate.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunBypassMode, v => v.togBypassMode.IsChecked).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.TunBypassMode, v => v.gridTunModeDirect.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.TunBypassMode2, v => v.gridTunModeProxy.Visibility, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunDirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunDirectProcess, v => v.txtDirectProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunDirectDNS, v => v.txtDirectDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyIP, v => v.txtProxyIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyProcess, v => v.txtProxyProcess.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunProxyDNS, v => v.txtProxyDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables);
@@ -162,9 +195,9 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
}); });
} }
private void linkDnsObjectDoc_Click(object sender, RoutedEventArgs e) private void linkDnsObjectDoc_Click(object sender, RoutedEventArgs e)
{ {
Utils.ProcessStart("https://www.v2fly.org/config/dns.html#dnsobject"); Utils.ProcessStart("https://www.v2fly.org/config/dns.html#dnsobject");
@@ -174,13 +207,14 @@ namespace v2rayN.Views
{ {
this.Close(); this.Close();
} }
private void btnBrowse_Click(object sender, System.Windows.RoutedEventArgs e) 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.Filter = "tunConfig|*.json|All|*.*";
openFileDialog1.ShowDialog(); openFileDialog1.ShowDialog();
txtCustomTemplate.Text = openFileDialog1.FileName; txtCustomTemplate.Text = openFileDialog1.FileName;
} }
} }
} }

View File

@@ -44,6 +44,5 @@
IsCancel="True" IsCancel="True"
IsDefault="True" IsDefault="True"
Style="{StaticResource MaterialDesignFlatButton}" /> Style="{StaticResource MaterialDesignFlatButton}" />
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -9,4 +9,4 @@ namespace v2rayN.Views
InitializeComponent(); InitializeComponent();
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More