Compare commits

...

306 Commits
6.31 ... 6.57

Author SHA1 Message Date
2dust
c22b57927c up 6.57 2024-09-04 16:23:10 +08:00
2dust
81b84d235c Code clean 2024-09-04 16:15:31 +08:00
2dust
488e8aab00 Improvement check updates 2024-09-04 15:47:17 +08:00
Wydy
fc43a9a726 Update pac.txt (#5636) 2024-09-04 09:42:54 +08:00
2dust
31947fdcb3 Bug fix
https://github.com/2dust/v2rayN/issues/5635
2024-09-03 19:30:23 +08:00
2dust
34c7963d28 Bug fix
https://github.com/2dust/v2rayN/issues/5627
2024-09-03 16:14:49 +08:00
2dust
d91b0afb9a Improved log message display 2024-09-03 16:03:26 +08:00
2dust
82eb3fd6bd Unified processing version 2024-09-03 10:16:50 +08:00
2dust
3d3d3f83df Bug fix
https://github.com/2dust/v2rayN/issues/5619#issuecomment-2323968966
2024-09-02 15:10:34 +08:00
2dust
6879c75bc8 Using Queues to Improve Message Display 2024-09-02 14:20:09 +08:00
2dust
b02ad6cdab up 6.56 2024-09-01 19:56:11 +08:00
2dust
f7b16952ea PackageReference 2024-09-01 19:51:18 +08:00
2dust
f0d05a7d4e Refactor check updates 2024-09-01 16:39:45 +08:00
2dust
d6ca317b20 xray mux add more option
https://github.com/2dust/v2rayN/issues/5565
2024-08-31 10:12:21 +08:00
2dust
2879fddfd9 sinb-box mux add padding option
https://github.com/2dust/v2rayN/issues/5544
2024-08-31 09:38:15 +08:00
2dust
b6c09470fc Add global exception catching 2024-08-30 13:47:53 +08:00
2dust
9fdf6c6c32 Bug fix 2024-08-30 13:15:25 +08:00
2dust
79085af994 Bug fix 2024-08-30 12:59:43 +08:00
2dust
d189f4b443 Add custom config Socks port to the group
https://github.com/2dust/v2rayN/issues/5576
2024-08-30 10:12:40 +08:00
2dust
c9d65e5cd9 Fix
https://github.com/2dust/v2rayN/issues/5595
2024-08-30 09:31:44 +08:00
2dust
639d62588a Refactor click event 2024-08-29 20:32:00 +08:00
2dust
6c9db51fd5 Creating a new desktop app with avaloniaui 2024-08-29 15:48:51 +08:00
2dust
f0dbb6b22c Bug fix 2024-08-29 15:19:03 +08:00
2dust
f10f7b6268 Add Portable Mode for mihomo 2024-08-29 10:10:55 +08:00
2dust
48a5cbc552 Check for standalone windows .Net version 2024-08-29 10:09:45 +08:00
2dust
6721d150e0 Refactor QRCodeHelper 2024-08-28 10:20:37 +08:00
2dust
54c16cad7d Adding OSPlatform Processing 2024-08-27 19:44:50 +08:00
2dust
ae3ab15245 Add Socks Protocol string 2024-08-27 16:09:07 +08:00
2dust
d3c0f50fec Adjustment of server binding 2024-08-27 13:18:18 +08:00
2dust
43753b1b7a Add linux download url 2024-08-27 13:06:39 +08:00
2dust
6f3e4b3682 Adding OSPlatform Processing 2024-08-26 18:45:41 +08:00
2dust
b57cdd31bd Refactor_updateView to add task 2024-08-22 19:51:10 +08:00
2dust
b936c194e4 Refactor v2rayUpgrade 2024-08-22 15:23:29 +08:00
2dust
064431421a Bug fix 2024-08-21 21:12:01 +08:00
TTG
9d49c7aad0 Update custom_routing_white (#5566) 2024-08-21 11:18:15 +08:00
2dust
a6f27e5071 Code clean 2024-08-20 14:30:45 +08:00
2dust
8d1d10b783 Refactoring Project 2024-08-20 14:15:29 +08:00
2dust
61bea05f63 Refactoring Project 2024-08-19 18:15:54 +08:00
2dust
bbe7c7b884 Optimized code 2024-08-18 15:04:56 +08:00
Milinda Brantini
a432852b78 Update cidr for direct outboundTag (#5550)
Signed-off-by: Milinda Brantini <C_A_T_T_E_R_Y@outlook.com>
2024-08-18 09:59:33 +08:00
2dust
770e8b8cfa >Export Base64-encoded Share Links to Clipboard 2024-08-17 20:53:42 +08:00
2dust
7faabdc375 Refactor code to decouple view and viewmodel 2024-08-17 10:53:02 +08:00
2dust
a9860418ba Optimized code 2024-08-15 21:03:00 +08:00
2dust
30ff9d0ea9 Optimized code
CoreInfoHandler
2024-08-15 20:13:59 +08:00
2dust
bbc2298939 Bug fix
https://github.com/2dust/v2rayN/issues/5517
2024-08-15 13:58:07 +08:00
2dust
3286e8e24d Refactor code to decouple view and viewmodel 2024-08-15 13:51:30 +08:00
2dust
372f3991e1 Refactor code to decouple view and viewmodel 2024-08-12 20:25:31 +08:00
2dust
9aa5c0d135 Refactor code to decouple view and viewmodel 2024-08-11 20:44:29 +08:00
2dust
9e9808e489 Refactor code to decouple view and viewmodel 2024-08-11 15:45:55 +08:00
2dust
3dd75b17cf Clean code 2024-08-10 19:20:31 +08:00
2dust
2504b4737b Refactor code to decouple view and viewmodel 2024-08-10 14:44:25 +08:00
2dust
8ff04dca0d Refactor code to decouple view and viewmodel 2024-08-10 10:02:00 +08:00
2dust
d893ee4829 up 6.55 2024-08-05 14:41:54 +08:00
2dust
dfc5ec0705 Improve UI 2024-08-05 14:39:04 +08:00
2dust
8023eb74c9 Bug fix 2024-08-04 19:26:01 +08:00
2dust
bb4d3997ad Bug fix
https://github.com/2dust/v2rayN/issues/5467
2024-08-04 09:40:33 +08:00
2dust
7ede3af762 up 6.54 2024-08-03 16:02:42 +08:00
2dust
97ea1c7a9e Add toolTip 2024-08-03 15:59:00 +08:00
2dust
43bb2c0fb8 Bug fix
https://github.com/2dust/v2rayN/issues/5462
2024-08-03 15:37:47 +08:00
2dust
6e7196bb27 Bug fix
https://github.com/2dust/v2rayN/issues/5437
2024-07-31 20:13:41 +08:00
2dust
87a71d58e8 Fix
https://github.com/2dust/v2rayN/issues/5438
2024-07-30 16:22:54 +08:00
2dust
32ffd43fe3 Bug fix
https://github.com/2dust/v2rayN/issues/5425
2024-07-30 16:06:43 +08:00
2dust
6500c8d85e up 6.53 2024-07-26 11:05:53 +08:00
2dust
9866d436da Add Outbound DNS address
https://github.com/2dust/v2rayN/issues/5387
2024-07-26 11:00:07 +08:00
2dust
0f4884d9d8 Improve and refactor the code 2024-07-25 10:26:39 +08:00
2dust
5a81441351 Adjust resx 2024-07-24 20:14:07 +08:00
2dust
e8721bfb6b Default dns changed to whitelist 2024-07-24 20:01:26 +08:00
2dust
1b09d95209 Improve UI 2024-07-24 19:51:13 +08:00
Jabin Kong
35f3b5a50e 1 (#5394) 2024-07-23 20:41:00 +08:00
2dust
ff5203a561 alpn h2,h3 2024-07-23 20:33:02 +08:00
2dust
c3c1ced309 up 6.52 2024-07-21 15:15:51 +08:00
2dust
08b1c8ec83 Improve latency testing 2024-07-21 15:15:00 +08:00
NagisaEfi
1dd3ee4e0a Update English translations (#5381)
* Update ResUI.resx

* Update ResUI.resx
2024-07-21 11:48:55 +08:00
Random Guy
06d0c6517d fix: add real delay test for custom config (#5377) 2024-07-21 11:44:12 +08:00
2dust
4938ce6364 Code clean 2024-07-21 11:37:11 +08:00
2dust
25f3fc354f Add multi-server load balancing 2024-07-21 11:26:10 +08:00
2dust
ad1a1f8015 Main window layout orientation setting 2024-07-19 20:31:07 +08:00
2dust
5c070e2ca8 Improve UI 2024-07-19 10:51:14 +08:00
2dust
70ea21fca2 Improve UI 2024-07-18 19:59:46 +08:00
2dust
bc3593871b Refactor the main interface 2024-07-18 17:39:11 +08:00
2dust
355a424be2 Code clean 2024-07-18 17:31:49 +08:00
2dust
0ffa9a0cc8 Remove unused resx
Remove Batch export subscription to clipboard
2024-07-15 20:17:55 +08:00
2dust
72fecb2b9a Add clash_mode to rule 2024-07-14 20:17:48 +08:00
2dust
4e9dfe5478 Improve 2024-07-14 17:16:07 +08:00
2dust
c79e2e3ad4 Add functionality multi-server set as active
Implemented using sing-box Selector, which can be switched using the clash api
2024-07-14 16:13:28 +08:00
2dust
7c33c1c322 Add reload for ClashProxiesView 2024-07-14 14:28:45 +08:00
2dust
ea32f75925 Code clean 2024-07-14 11:00:22 +08:00
2dust
7eaed21b9a Improve 2024-07-14 10:59:36 +08:00
2dust
cfe8fcd28d up 6.51 2024-07-12 14:23:29 +08:00
2dust
9f4718af70 Code clean
Add allowInsecure to Share
2024-07-11 14:42:01 +08:00
2dust
39faccfd0b Bug fix 2024-07-10 17:32:26 +08:00
2dust
7545763dae Default domain strategy for resolving the outbound domain names -- singbox 2024-07-08 18:45:29 +08:00
2dust
c2928be35d Log messages are not displayed when in the background 2024-07-08 17:16:49 +08:00
2dust
449bb40d48 sing-box prioritizes the use of local srs 2024-07-08 14:20:41 +08:00
2dust
4caf1a1e63 Improve and refactor the code 2024-07-08 09:52:11 +08:00
2dust
01b205e6f1 Adjust information DispatcherPriority 2024-07-07 21:11:04 +08:00
2dust
160d3843a6 Bug fix 2024-07-05 15:28:28 +08:00
2dust
5efb784115 up 6.50 2024-07-05 11:18:36 +08:00
2dust
acde5b8384 Bug fix 2024-07-05 11:18:14 +08:00
2dust
373ee6586a Optimize system proxy code 2024-07-04 17:07:05 +08:00
2dust
215308c329 Change srs source
https://github.com/2dust/sing-box-rules
2024-07-04 16:27:44 +08:00
2dust
478cadba5e Bug fix 2024-06-30 20:43:06 +08:00
2dust
f4af4da791 Adjust res 2024-06-30 10:00:28 +08:00
2dust
22d4f435de Add tun and mixin functions to clash 2024-06-28 20:29:44 +08:00
2dust
ccb8cd5c04 up 6.49 2024-06-28 16:14:45 +08:00
2dust
e963f9e349 Add clash display in the main interface 2024-06-28 16:14:19 +08:00
2dust
e3c2a4b8da Bug fix 2024-06-28 10:41:17 +08:00
2dust
324f46cdad Bug fix
https://github.com/2dust/v2rayN/discussions/5268
2024-06-27 17:59:39 +08:00
2dust
691b19b5fd Adding support for the clash proxies interface 2024-06-27 16:36:36 +08:00
2dust
63ed2311dc Bug fix 2024-06-26 16:00:37 +08:00
2dust
d59e59ca40 up 6.48 2024-06-24 17:42:37 +08:00
2dust
c9a278b4a2 Check for updates mihomo 2024-06-24 17:41:53 +08:00
2dust
8ee5304148 Bug fix 2024-06-24 16:42:17 +08:00
2dust
3beaa8145f Bug fix 2024-06-24 16:19:00 +08:00
2dust
e30c55a0af up 6.47 2024-06-24 15:34:41 +08:00
2dust
b583590a64 Update ConfigHandler.cs
https://github.com/2dust/v2rayN/pull/5264
2024-06-24 15:25:00 +08:00
OnceUponATimeInAmerica
a28c63168a Support for setting subs-group remarks (group's name) from the (optional) "remark" query parameter in the pasted subs url (#5264) 2024-06-24 15:20:16 +08:00
2dust
620422350f Improved tun mode
Enabling tun mode.
Only one core will be run when using sing-box core;
When using a non-sing-box, the sing-box will be used to start an additional front Socks service to provide a tun entry, which will then run two cores
2024-06-24 15:19:42 +08:00
2dust
b77cc3c33b Add network attribute to route rule
https://github.com/2dust/v2rayN/discussions/5256
2024-06-22 16:44:15 +08:00
2dust
71bf9b4887 up 6.46 2024-06-21 16:02:08 +08:00
2dust
9039d401da set DOTNET_EnableWriteXorExecute=0 under win10
https://github.com/2dust/v2rayN/issues/5186
2024-06-21 14:09:57 +08:00
2dust
74a0a93201 Improve and refactor the code 2024-06-21 11:15:35 +08:00
2dust
522571f0b3 Add splithttp transport for xray
https://github.com/XTLS/Xray-core/releases/tag/v1.8.15
2024-06-20 16:20:05 +08:00
Lsyx-Good
123c49c22d Adjust singbox DNS server and rule position (#5229) 2024-06-20 16:08:08 +08:00
OnceUponATimeInAmerica
1ff88d29be Extend stats reporting to support custom configs with several load-balanced outbounds in them, with tags starting with "proxy" e.g. proxy1, proxy2 (fully compatible with existing configs) (#5225) 2024-06-20 15:32:10 +08:00
Lsyx-Good
63d5a2a1be Fix bug (#5213) 2024-06-10 15:12:39 +08:00
2dust
1e9a6cb06b Refactor code 2024-06-04 09:48:04 +08:00
2dust
31748aa660 Refactor code 2024-06-03 17:50:18 +08:00
2dust
d0c6ea6a63 remove http://cachefly.cachefly.net/100mb.test 2024-06-03 14:06:59 +08:00
2dust
7ffe286a56 Up PackageReference 2024-06-03 07:37:49 +08:00
2dust
b99b30163b Bug fix 2024-06-03 07:37:26 +08:00
kirilllivanov
83b4f1e660 Fix incorrect filenames (#5122) 2024-05-18 17:11:38 +08:00
2dust
b57ba6a98b up 6.45 2024-05-18 09:53:15 +08:00
2dust
d748e6eff4 Add destOverride 2024-05-14 15:31:19 +08:00
2dust
315d4b75b2 Optimize code 2024-05-14 13:42:42 +08:00
2dust
31267cbc33 Adjust Scan screen qrcode 2024-05-12 17:07:56 +08:00
2dust
c23379b3b6 Adjust sing-box dns 2024-05-12 15:42:28 +08:00
2dust
568144d6a2 TransitionAssist DisableTransitions 2024-05-12 14:59:23 +08:00
2dust
5857042963 Up 6.44 2024-05-08 13:40:24 +08:00
2dust
28e41dc621 Add open the file location 2024-05-08 11:43:03 +08:00
2dust
baef3b364b Bug fix 2024-05-08 11:42:01 +08:00
2dust
4b9ddb803f Bug fix 2024-05-07 14:15:08 +08:00
2dust
c07c7ad82f Added reminder that a reboot is required to modify settings 2024-05-06 17:19:29 +08:00
2dust
e223b80b95 Merge pull request #5066 from sincereliu/master
Optimize code for better performance
2024-05-06 09:55:30 +08:00
sincere liu
5fe468fa1b Optimize code for better performance 2024-05-05 22:07:51 +08:00
2dust
60068d8d16 Themes migrate 2024-05-05 16:19:47 +08:00
2dust
b6c5b46afe Up PackageReference 2024-05-05 10:10:19 +08:00
2dust
124cbfadb4 Add custom sing-box rule-set support 2024-05-04 13:54:22 +08:00
2dust
8d21f9b900 Bug fix 2024-05-04 13:24:13 +08:00
2dust
398dbbd2e5 Bug fix
https://github.com/2dust/v2rayN/issues/5035
2024-05-03 10:29:32 +08:00
2dust
e9b392d1c0 Optimized sorted storage 2024-04-30 14:44:02 +08:00
2dust
9d7c7e3225 Adjust the experimental and mux of sing-box 2024-04-27 10:05:13 +08:00
2dust
855fd4f0b7 Merge pull request #5026 from GibMeMyPacket/feat/singbox/exp_cachefile
Add `Enable cache file for sing-box`
2024-04-27 09:42:31 +08:00
GibMeMyPacket
807839929d Add Enable cache file for sing-box 2024-04-25 12:07:53 +00:00
2dust
870955fee1 Bug fix 2024-04-11 08:07:21 +08:00
2dust
e0cea929ea Up 6.43 2024-04-10 13:52:38 +08:00
2dust
315f4c35f0 Code clean 2024-04-10 13:32:50 +08:00
2dust
d961ea22a6 Built-in routing rule set upgraded to V2 2024-04-10 10:50:52 +08:00
2dust
5c0c07c78f Migrate geosite & geoip to rule sets (sing-box) 2024-04-10 08:42:53 +08:00
2dust
bba93a0fb7 Added tls fragment support (Xray-core)
https://github.com/2dust/v2rayN/issues/4900
2024-04-08 17:06:48 +08:00
2dust
5683df2fc0 Added outbound HTTP support (support group prefix proxy)
https://github.com/2dust/v2rayN/discussions/4550
2024-04-08 14:02:56 +08:00
2dust
b5cb9ce67e Set autoHideStartup default value is false 2024-04-05 17:24:53 +08:00
2dust
06a32dc895 Adjust sing-box dns default example 2024-04-05 11:05:45 +08:00
2dust
dff12a8a3a fix
https://github.com/2dust/v2rayN/issues/4928
2024-04-05 11:04:35 +08:00
2dust
dc3f07ee84 Bug fix 2024-04-03 09:51:07 +08:00
2dust
1aef49ee11 Custom configuration file to use Xray prefix in non-Tun mode
https://github.com/2dust/v2rayN/issues/4855
2024-04-01 08:22:14 +08:00
2dust
ee3159b00e Update 6.42 2024-03-31 17:26:02 +08:00
2dust
86d2c307f1 Bug fix 2024-03-31 17:23:33 +08:00
2dust
7823a217b4 Update 6.41 2024-03-31 08:09:13 +08:00
2dust
2004df8337 Rename Model to Models 2024-03-31 08:08:06 +08:00
2dust
13bc2d0340 Bug fix
https://github.com/2dust/v2rayN/issues/4902
2024-03-31 07:54:22 +08:00
2dust
edbc850346 Update 6.40 2024-03-30 18:12:37 +08:00
2dust
901d3c85ca Up PackageReference 2024-03-30 16:15:13 +08:00
2dust
abbe83f3c2 Fixed issues with multi-core traffic processing 2024-03-30 16:00:19 +08:00
2dust
bb3a04a9c8 Bug fix for exit app 2024-03-30 15:26:12 +08:00
2dust
bac13e8b71 Rename Utile to Utils 2024-03-26 14:26:03 +08:00
2dust
3871681de3 Improve remove Application.Current.Shutdown 2024-03-26 14:22:53 +08:00
2dust
ae6f2b6df6 Up PackageReference 2024-03-26 14:19:14 +08:00
2dust
f59bbc9981 Add authority for grpc 2024-03-23 18:26:44 +08:00
2dust
eac0c84e11 Improve IsNullOrEmpty 2024-03-23 18:26:04 +08:00
2dust
f814cc443d Improve 2024-03-23 10:47:06 +08:00
2dust
262466303b Import Multiple Custom v2ray-core Json Configs from Subscription
https://github.com/2dust/v2rayN/issues/4745
2024-03-23 10:46:45 +08:00
2dust
3b4cc2c5f2 Merge pull request #4848 from 1208nn/patch-2
Update schdtask related code
2024-03-16 16:25:58 +08:00
ShH Y
023d3fbf6f Update Utile.cs 2024-03-16 11:38:41 +08:00
2dust
fe01f290bc Improve 2024-03-13 16:38:37 +08:00
2dust
5805ac9f7f Update 6.39 2024-03-12 09:19:19 +08:00
2dust
4e2f38a343 Clean 2024-03-12 09:14:21 +08:00
2dust
572c924e5c Add httpupgrade 2024-03-12 09:05:59 +08:00
2dust
e90353e550 Bug fix 2024-03-11 14:46:24 +08:00
2dust
f8ae1b8c49 Bug fix 2024-03-11 08:34:07 +08:00
2dust
186d995919 Improve 2024-03-09 14:30:39 +08:00
2dust
70584aff9d Refactor 2024-03-09 10:12:45 +08:00
2dust
dcdc63785a HTTP port=SOCKS port+1;Pac port=SOCKS port+4;API port=SOCKS port+5; 2024-03-09 09:40:19 +08:00
2dust
0e7bfa65de Refactor 2024-03-09 09:27:55 +08:00
2dust
9427340ab7 Update 6.38 2024-03-08 09:55:13 +08:00
2dust
63af5bae8a Bug fix 2024-03-08 09:41:38 +08:00
2dust
9232f1fa40 Merge pull request #4802 from Array-Cats/master
Update README.md
2024-03-08 09:40:28 +08:00
Array-Cats
15bdb551f4 Update README.md 2024-03-07 23:56:58 +08:00
2dust
2cda2b53ed Improve 2024-03-07 11:51:45 +08:00
2dust
028c9ea0b5 Bug fix 2024-03-07 09:06:35 +08:00
2dust
315b51e7ca Up PackageReference 2024-03-05 09:45:27 +08:00
2dust
0185b3b145 Remove some pop-up messages 2024-03-04 10:41:42 +08:00
2dust
afaad49879 Bug fix 2024-03-02 10:35:33 +08:00
2dust
4b2b45979b Return api port=socks port +11 2024-03-02 10:00:28 +08:00
2dust
66e40edd0e Bug fix singbox transport type http 2024-03-02 09:58:50 +08:00
2dust
3d5168885f up 6.37 2024-02-29 17:25:50 +08:00
2dust
6eee2c2342 Add obfs=http support for sing-box ss 2024-02-29 10:11:27 +08:00
2dust
11ec27147a Use Global.None instead of none 2024-02-29 09:43:04 +08:00
2dust
a522a02ba2 Temporarily add compatibility to VLESS 2024-02-29 09:39:12 +08:00
2dust
5ff4d35a30 Added termination speed test 2024-02-25 18:28:59 +08:00
2dust
4c5546bf52 Merge pull request #4757 from NagisaEfi/master
Update translation
2024-02-25 09:28:06 +08:00
NagisaEfi
ab37a46e83 Update translation 2024-02-23 23:46:44 +08:00
2dust
0b3635b5c5 Bug fix 2024-02-21 10:17:28 +08:00
2dust
2a338d9a83 Merge pull request #4743 from NagisaEfi/master
Localization (CHT and ENG)
2024-02-20 16:46:17 +08:00
NagisaEfi
7031a4c26c Localization (CHT and ENG) 2024-02-20 15:59:35 +08:00
2dust
2c5ca97476 Merge pull request #4738 from NimaZare/master
spell check and update
2024-02-20 13:07:28 +08:00
NimaZare
fc0c8f6bb1 spell check and update 2024-02-19 13:13:36 +03:30
2dust
643547704e Up 6.36 2024-02-18 11:09:00 +08:00
2dust
4717b63775 Bug fix 4 mihomo 2024-02-18 11:02:50 +08:00
2dust
4af148f480 Bug fix 2024-02-15 10:34:43 +08:00
2dust
a9c59693ee Bug fix 2024-02-13 10:11:17 +08:00
2dust
9b3ac159c1 Merge pull request #4712 from hxdhttk/hxdhttk/statePortConf
Fix the state ports conflicts when multiple `v2rayN` instances start in a short period.
2024-02-13 09:57:59 +08:00
2dust
c03c98157f Merge pull request #4711 from hxdhttk/hxdhttk/mixedStdErr
Fix misleading "Cannot mix synchronous and asynchronous operation on process stream." logs.
2024-02-13 09:47:19 +08:00
Minghao Hu
74149b761f Resolve the StatePort when the other components call it. 2024-02-12 22:49:57 +09:00
Minghao Hu
44cfa2d8dc Add a start up error receiver. 2024-02-12 22:12:57 +09:00
Minghao Hu
b0fb00d597 Merge new commits. 2024-02-12 21:20:16 +09:00
2dust
af3c1dc039 Bug fix
https://github.com/2dust/v2rayN/issues/4707
2024-02-12 08:49:22 +08:00
2dust
1c94b5d5f0 Up 6.35 2024-02-10 17:07:30 +08:00
2dust
fbb00c0f85 Improve 2024-02-10 16:57:26 +08:00
2dust
4a72e63d1c When updating a subscription, only determine whether the alias already exists 2024-02-09 09:57:28 +08:00
2dust
ce94e0ba4d Refactor 2024-02-08 16:22:38 +08:00
2dust
e2c836794b Refactor 2024-02-08 14:01:33 +08:00
2dust
05e424f805 Bug fix 2024-02-08 09:32:01 +08:00
2dust
bf30819a4a Bug fix
https://github.com/2dust/v2rayN/issues/4334
2024-02-05 20:24:30 +08:00
2dust
52e9d30b46 Improve 2024-02-04 10:02:02 +08:00
2dust
1fa2d55e1d Up PackageReference 2024-02-03 10:27:40 +08:00
2dust
4d0ee652d8 Bug fix 2024-02-03 10:26:37 +08:00
2dust
ff215bc9aa Remove ping test 2024-02-02 10:39:07 +08:00
2dust
e1cadc878a Improve VmessQRCode json 2024-02-02 10:21:13 +08:00
2dust
57d9d8ddb9 Improve 2024-02-01 12:44:47 +08:00
2dust
f76b1a5363 Add editing subscription in the main interface 2024-01-31 10:16:21 +08:00
2dust
9b579be2be Try to remove the tun device when turning on 2024-01-31 09:56:47 +08:00
2dust
9d43465eab Improve 2024-01-30 18:29:52 +08:00
2dust
fc52870431 Add setting 4 SpeedPingTestUrl 2024-01-30 18:04:10 +08:00
2dust
c466ea100a Refactor 2024-01-30 17:18:00 +08:00
2dust
4054369611 Up PackageReference 2024-01-29 17:20:15 +08:00
2dust
11106937a3 Improve 2024-01-29 11:50:24 +08:00
2dust
fdddf901f3 Remove the main interface Encryption Method 2024-01-29 11:15:11 +08:00
2dust
2e30c04238 Migrate from Newtonsoft.Json to System.Text.Json 2024-01-28 19:53:20 +08:00
2dust
bd838094cd bug fix 2024-01-27 18:29:17 +08:00
2dust
6f22b74154 Improve 2024-01-27 10:57:40 +08:00
2dust
e71525db0e Refactor 2024-01-25 17:28:06 +08:00
2dust
d7c1516ec2 bug fix for test shadowsocks 2024-01-23 12:30:11 +08:00
2dust
ff91a5dad9 Add obfs 4 hysteria2 2024-01-22 18:45:22 +08:00
2dust
d76679c2b6 Fill alpns & bug fix 2024-01-20 17:43:42 +08:00
2dust
d7cb88f0a4 Bug fix 2024-01-20 09:45:00 +08:00
2dust
8a3eb41314 Add Wireguard uri 2024-01-16 11:05:51 +08:00
2dust
e2f9aac1c9 remove System.Web 2024-01-16 11:05:02 +08:00
2dust
08c7396404 Add mtu setting 4 Wireguard 2024-01-15 17:11:00 +08:00
2dust
69cbdbd20e Added Wireguard support (using sing-box) 2024-01-14 17:33:41 +08:00
2dust
005f26ba7c bug fix 2024-01-14 10:23:46 +08:00
2dust
a1dc0c8104 Update ResUI.resx 2024-01-14 10:04:02 +08:00
2dust
75435b8fe0 Merge pull request #4621 from yscjr/master
修改修改非管理员模式下tun模式启动逻辑;缩短自动隐藏时间
2024-01-14 10:00:09 +08:00
John Edwerd
6d7385788e 修改修改非管理员模式下tun模式启动逻辑;缩短自动隐藏时间 2024-01-13 21:54:03 +08:00
2dust
726d9d410f Refactor 2024-01-13 16:52:42 +08:00
2dust
ee2a61bb61 bug fix 2024-01-12 18:22:23 +08:00
2dust
40748d6e42 Update ResUI.zh-Hant.resx 2024-01-12 18:06:35 +08:00
2dust
02225ad0b8 Refactor 2024-01-11 18:34:33 +08:00
2dust
3c4703ad85 Optimize code 2024-01-11 18:24:32 +08:00
2dust
6762f35ade Optimize code 2024-01-10 17:44:55 +08:00
2dust
5135afcf8f Refactor 2024-01-10 16:32:26 +08:00
2dust
4aae82e0cc Adjust Tool code 2024-01-10 10:56:10 +08:00
2dust
ea95c6de79 Refactor Utils 2024-01-10 10:43:48 +08:00
2dust
4a67e963ed Up TargetFramework to net8.0 2024-01-10 10:01:59 +08:00
2dust
720f177d65 Merge pull request #4603 from ShiinaRinne/hysteria2_uri
fix https://github.com/2dust/v2rayN/issues/4590
2024-01-10 09:55:51 +08:00
ShiinaRinne
2b4a043a92 fix https://github.com/2dust/v2rayN/issues/4590 2024-01-09 23:20:30 +08:00
2dust
77b20bc562 Merge pull request #4594 from yin1999/bump-action
build(ci): bump actions/upload-artifact from v3 to v4
2024-01-09 09:57:45 +08:00
Allo
063449448a build(ci): bump actions/upload-artifact from v3 to v4 2024-01-08 21:35:28 +08:00
2dust
559ffcbab5 up 6.33 2024-01-06 13:47:03 +08:00
2dust
80ed8346be Bug fix 2024-01-06 10:41:07 +08:00
2dust
a49455f330 Code clean 2024-01-05 13:48:42 +08:00
2dust
c3de6f6d02 Merge pull request #4568 from ShiinaRinne/theme
fix: 当关闭"是否跟随系统主题"时,无法应用"暗黑模式"的设置
2024-01-03 20:07:43 +08:00
2dust
ee416b1bf2 Merge pull request #4567 from ShiinaRinne/patch-2
添加ico格式的自定义图标支持
2024-01-03 20:06:54 +08:00
2dust
784928ffc8 Merge pull request #4571 from canmengxian/patch-2
禁用删除工作流运行
2024-01-03 20:06:34 +08:00
残梦
609360a1d0 禁用删除工作流运行 2024-01-02 23:52:14 +08:00
ShiinaRinne
18ce2f7b1c fix: 当关闭"是否跟随系统主题"时,无法应用"暗黑模式"的设置 2024-01-02 15:34:42 +08:00
ShiinaRinne
78625d82ae 添加ico格式的自定义图标支持 2024-01-02 15:03:21 +08:00
2dust
2ca34fb9ad Bug fix 2023-12-29 18:16:02 +08:00
2dust
f5f944aa50 up 6.32 2023-12-29 10:02:24 +08:00
2dust
83b4ab83d1 Improve speed test,add Hy2 and Tuic test 2023-12-29 09:39:55 +08:00
2dust
34f63f9006 Add ipv6 option for Tun mode 2023-12-26 18:13:12 +08:00
2dust
b74188d904 Previous and next proxy 4 sing-box 2023-12-25 16:42:23 +08:00
Minghao Hu
ba246e99e8 Fix mixed sync/async ops on Process streams. 2023-12-24 16:21:21 +09:00
2dust
51576b54c3 Previous and next proxy setting 2023-12-24 10:34:55 +08:00
2dust
0d5a9fcf4a Previous and next proxy 2023-12-23 20:57:31 +08:00
2dust
b0c5f74edb Refactor 2023-12-23 17:49:39 +08:00
2dust
1ac7661593 Refactor 2023-12-23 10:19:41 +08:00
2dust
caa2c523f4 Remove singbox update geo file 2023-12-22 16:56:09 +08:00
2dust
7b9f1e6788 Refactor 2023-12-22 16:03:25 +08:00
2dust
86f3ed29f9 Adjust cores 2023-12-22 12:13:36 +08:00
2dust
655d411afe Fix something 2023-12-22 09:46:55 +08:00
2dust
f5deb8e168 Code clean 2023-12-19 18:09:11 +08:00
2dust
fcdb61bfbf Code clean 2023-12-19 16:49:45 +08:00
2dust
bd9a4ca094 Added Tuic v5 support (using sing-box) 2023-12-19 16:03:30 +08:00
2dust
e2657e746d UI adjust 2023-12-16 17:45:52 +08:00
2dust
6f5a174231 Update Package Reference 2023-12-16 17:45:29 +08:00
275 changed files with 44523 additions and 12974 deletions

View File

@@ -18,13 +18,13 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: 删除工作流运行 # - name: 删除工作流运行
uses: Mattraks/delete-workflow-runs@v2 # uses: Mattraks/delete-workflow-runs@v2
with: # with:
token: ${{ github.token }} # token: ${{ github.token }}
repository: ${{ github.repository }} # repository: ${{ github.repository }}
retain_days: 0 # retain_days: 0
keep_minimum_runs: 1 # keep_minimum_runs: 1
- name: Build - name: Build
run: cd v2rayN && run: cd v2rayN &&
@@ -36,13 +36,12 @@ jobs:
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory # 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: v2rayN name: v2rayN
path: path: |
.\v2rayN\v2rayN.zip .\v2rayN\v2rayN.zip
# - name: Release # - name: Release
# uses: softprops/action-gh-release@v1 # uses: softprops/action-gh-release@v1
# env: # env:
@@ -58,4 +57,4 @@ jobs:
# * This is an automated deployment of GitHub Actions, the change log should be updated manually soon # * This is an automated deployment of GitHub Actions, the change log should be updated manually soon
# ## 更新日志 # ## 更新日志
# * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新 # * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新

View File

@@ -14,7 +14,8 @@ A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core)
- Run v2rayN.exe - Run v2rayN.exe
## Requirements ## Requirements
- [Microsoft .NET 6.0 Desktop Runtime ](https://download.visualstudio.microsoft.com/download/pr/513d13b7-b456-45af-828b-b7b7981ff462/edf44a743b78f8b54a2cec97ce888346/windowsdesktop-runtime-6.0.15-win-x64.exe) - (6.35 and above)[Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- (6.33 and below)[Microsoft .NET 6.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) - [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
@@ -9,9 +9,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.25.1" /> <PackageReference Include="Google.Protobuf" Version="3.28.0" />
<PackageReference Include="Grpc.Net.Client" Version="2.59.0" /> <PackageReference Include="Grpc.Net.Client" Version="2.65.0" />
<PackageReference Include="Grpc.Tools" Version="2.59.0"> <PackageReference Include="Grpc.Tools" Version="2.66.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

@@ -0,0 +1,11 @@
using ReactiveUI;
namespace ServiceLib.Base
{
public class MyReactiveObject : ReactiveObject
{
protected static Config? _config;
protected Func<EViewAction, object?, Task<bool>>? _updateView;
protected NoticeHandler? _noticeHandler;
}
}

View File

@@ -1,17 +1,16 @@
using Downloader; using Downloader;
using System.IO;
using System.Net; using System.Net;
namespace v2rayN.Base namespace ServiceLib.Common
{ {
internal class DownloaderHelper public class DownloaderHelper
{ {
private static readonly Lazy<DownloaderHelper> _instance = new(() => new()); private static readonly Lazy<DownloaderHelper> _instance = new(() => new());
public static DownloaderHelper Instance => _instance.Value; public static DownloaderHelper Instance => _instance.Value;
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout) public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
{ {
if (string.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
{ {
return null; return null;
} }
@@ -57,7 +56,7 @@ namespace v2rayN.Base
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout) public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
{ {
if (string.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
{ {
throw new ArgumentNullException(nameof(url)); throw new ArgumentNullException(nameof(url));
} }
@@ -120,11 +119,11 @@ namespace v2rayN.Base
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout) public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
{ {
if (string.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
{ {
throw new ArgumentNullException(nameof(url)); throw new ArgumentNullException(nameof(url));
} }
if (string.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
throw new ArgumentNullException(nameof(fileName)); throw new ArgumentNullException(nameof(fileName));
} }
@@ -169,11 +168,15 @@ namespace v2rayN.Base
{ {
progress.Report(101); progress.Report(101);
} }
else if (value.Error != null)
{
throw value.Error;
}
} }
}; };
using var cts = new CancellationTokenSource(); using var cts = new CancellationTokenSource();
await downloader.DownloadFileTaskAsync(url, fileName, cts.Token).WaitAsync(TimeSpan.FromSeconds(timeout), cts.Token); await downloader.DownloadFileTaskAsync(url, fileName, cts.Token);
downloadOpt = null; downloadOpt = null;
} }

View File

@@ -1,8 +1,7 @@
using System.IO; using System.IO.Compression;
using System.IO.Compression;
using System.Text; using System.Text;
namespace v2rayN.Tool namespace ServiceLib.Common
{ {
public static class FileManager public static class FileManager
{ {
@@ -15,12 +14,12 @@ namespace v2rayN.Tool
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return false; return false;
} }
public static void UncompressFile(string fileName, byte[] content) public static void UncompressedFile(string fileName, byte[] content)
{ {
try try
{ {
@@ -30,7 +29,23 @@ namespace v2rayN.Tool
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
}
}
public static void UncompressedFile(string fileName, string toPath, string? toName)
{
try
{
FileInfo fileInfo = new(fileName);
using FileStream originalFileStream = fileInfo.OpenRead();
using FileStream decompressedFileStream = File.Create(toName != null ? Path.Combine(toPath, toName) : toPath);
using GZipStream decompressionStream = new(originalFileStream, CompressionMode.Decompress);
decompressionStream.CopyTo(decompressedFileStream);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
} }
} }
@@ -49,7 +64,7 @@ namespace v2rayN.Tool
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
throw; throw;
} }
} }
@@ -75,13 +90,27 @@ namespace v2rayN.Tool
} }
catch (IOException ex) catch (IOException ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
return false;
}
return true;
}
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
{
try
{
ZipFile.CreateFromDirectory(sourceDirectoryName, destinationArchiveFileName);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return false; return false;
} }
return true; return true;

View File

@@ -1,9 +1,8 @@
using System.IO; using System.Net.Http.Headers;
using System.Net.Http;
using System.Net.Mime; using System.Net.Mime;
using System.Text; using System.Text;
namespace v2rayN.Base namespace ServiceLib.Common
{ {
/// <summary> /// <summary>
/// </summary> /// </summary>
@@ -21,26 +20,57 @@ namespace v2rayN.Base
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient; private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
public async Task<string?> TryGetAsync(string url)
{
if (string.IsNullOrEmpty(url))
return null;
try
{
HttpResponseMessage response = await httpClient.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
catch
{
return null;
}
}
public async Task<string?> GetAsync(string url) public async Task<string?> GetAsync(string url)
{ {
if (string.IsNullOrEmpty(url)) return null; if (Utils.IsNullOrEmpty(url)) return null;
return await httpClient.GetStringAsync(url); return await httpClient.GetStringAsync(url);
} }
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default) public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
{ {
if (string.IsNullOrWhiteSpace(url)) return null; if (Utils.IsNullOrEmpty(url)) return null;
return await client.GetStringAsync(url, token); return await client.GetStringAsync(url, token);
} }
public async Task PutAsync(string url, Dictionary<string, string> headers) public async Task PutAsync(string url, Dictionary<string, string> headers)
{ {
var jsonContent = Utils.ToJson(headers); var jsonContent = JsonUtils.Serialize(headers);
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json); var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
var result = await httpClient.PutAsync(url, content); var result = await httpClient.PutAsync(url, content);
} }
public async Task PatchAsync(string url, Dictionary<string, string> headers)
{
var myContent = JsonUtils.Serialize(headers);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
await httpClient.PatchAsync(url, byteContent);
}
public async Task DeleteAsync(string url)
{
await httpClient.DeleteAsync(url);
}
public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default) public static async Task DownloadFileAsync(HttpClient client, string url, string fileName, IProgress<double>? progress, CancellationToken token = default)
{ {
ArgumentNullException.ThrowIfNull(url); ArgumentNullException.ThrowIfNull(url);
@@ -76,19 +106,19 @@ namespace v2rayN.Base
//if (progressPercentage != percent && percent % 10 == 0) //if (progressPercentage != percent && percent % 10 == 0)
{ {
progressPercentage = percent; progressPercentage = percent;
progress!.Report(percent); progress?.Report(percent);
} }
} }
} }
if (canReportProgress) if (canReportProgress)
{ {
progress!.Report(101); progress?.Report(101);
} }
} }
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default) public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
{ {
if (string.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
{ {
throw new ArgumentNullException(nameof(url)); throw new ArgumentNullException(nameof(url));
} }

View File

@@ -1,7 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace v2rayN namespace ServiceLib.Common
{ {
/* /*
* See: * See:
@@ -52,7 +52,7 @@ namespace v2rayN
if (!succ) if (!succ)
{ {
Utils.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error());
} }
return succ; return succ;

View File

@@ -0,0 +1,133 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace ServiceLib.Common
{
public class JsonUtils
{
/// <summary>
/// DeepCopy
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static T DeepCopy<T>(T obj)
{
return Deserialize<T>(Serialize(obj, false))!;
}
/// <summary>
/// Deserialize to object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="strJson"></param>
/// <returns></returns>
public static T? Deserialize<T>(string? strJson)
{
try
{
if (string.IsNullOrWhiteSpace(strJson))
{
return default;
}
return JsonSerializer.Deserialize<T>(strJson);
}
catch
{
return default;
}
}
/// <summary>
/// parse
/// </summary>
/// <param name="strJson"></param>
/// <returns></returns>
public static JsonNode? ParseJson(string strJson)
{
try
{
if (string.IsNullOrWhiteSpace(strJson))
{
return null;
}
return JsonNode.Parse(strJson);
}
catch
{
//SaveLog(ex.Message, ex);
return null;
}
}
/// <summary>
/// Serialize Object to Json string
/// </summary>
/// <param name="obj"></param>
/// <param name="indented"></param>
/// <returns></returns>
public static string Serialize(object? obj, bool indented = true)
{
string result = string.Empty;
try
{
if (obj == null)
{
return result;
}
var options = new JsonSerializerOptions
{
WriteIndented = indented ? true : false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
result = JsonSerializer.Serialize(obj, options);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
return result;
}
/// <summary>
/// SerializeToNode
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
/// <summary>
/// Save as json file
/// </summary>
/// <param name="obj"></param>
/// <param name="filePath"></param>
/// <param name="nullValue"></param>
/// <returns></returns>
public static int ToFile(object? obj, string? filePath, bool nullValue = true)
{
if (filePath is null)
{
return -1;
}
try
{
using FileStream file = File.Create(filePath);
var options = new JsonSerializerOptions
{
WriteIndented = true,
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
};
JsonSerializer.Serialize(file, obj, options);
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return -1;
}
}
}
}

View File

@@ -1,9 +1,8 @@
using NLog; using NLog;
using NLog.Config; using NLog.Config;
using NLog.Targets; using NLog.Targets;
using System.IO;
namespace v2rayN.Tool namespace ServiceLib.Common
{ {
public class Logging public class Logging
{ {
@@ -51,5 +50,28 @@ namespace v2rayN.Tool
catch { } catch { }
}); });
} }
public static void SaveLog(string strContent)
{
if (LogManager.IsLoggingEnabled())
{
var logger = LogManager.GetLogger("Log1");
logger.Info(strContent);
}
}
public static void SaveLog(string strTitle, Exception ex)
{
if (LogManager.IsLoggingEnabled())
{
var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace);
if (ex?.InnerException != null)
{
logger.Error(ex.InnerException);
}
}
}
} }
} }

View File

@@ -0,0 +1,15 @@
using QRCoder;
namespace ServiceLib.Common
{
public class QRCodeHelper
{
public static byte[]? GenQRCode(string? url)
{
using QRCodeGenerator qrGenerator = new();
using QRCodeData qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q);
using PngByteQRCode qrCode = new(qrCodeData);
return qrCode.GetGraphic(20);
}
}
}

View File

@@ -1,7 +1,7 @@
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
namespace v2rayN.Tool namespace ServiceLib.Common
{ {
public static class QueryableExtension public static class QueryableExtension
{ {
@@ -29,22 +29,22 @@ namespace v2rayN.Tool
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(_GetLambda<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(_GetLambda<T, TProp>(memberProperty));
} }
private static Expression<Func<T, TProp>> _GetLamba<T, TProp>(PropertyInfo memberProperty) private static Expression<Func<T, TProp>> _GetLambda<T, TProp>(PropertyInfo memberProperty)
{ {
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception(); if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
var thisArg = Expression.Parameter(typeof(T)); var thisArg = Expression.Parameter(typeof(T));
var lamba = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg); var lambda = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
return lamba; return lambda;
} }
} }
} }

View File

@@ -1,6 +1,4 @@
using v2rayN.Base; namespace ServiceLib.Common
namespace v2rayN.Tool
{ {
public class SemanticVersion public class SemanticVersion
{ {
@@ -29,7 +27,7 @@ namespace v2rayN.Tool
this.minor = int.Parse(parts[1]); this.minor = int.Parse(parts[1]);
this.patch = 0; this.patch = 0;
} }
else if (parts.Length == 3) else if (parts.Length == 3 || parts.Length == 4)
{ {
this.major = int.Parse(parts[0]); this.major = int.Parse(parts[0]);
this.minor = int.Parse(parts[1]); this.minor = int.Parse(parts[1]);

View File

@@ -1,20 +1,21 @@
using SQLite; using SQLite;
using System.Collections; using System.Collections;
namespace v2rayN.Base namespace ServiceLib.Common
{ {
public sealed class SqliteHelper public sealed class SQLiteHelper
{ {
private static readonly Lazy<SqliteHelper> _instance = new(() => 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;
private SQLiteConnection _db; private SQLiteConnection _db;
private SQLiteAsyncConnection _dbAsync; private SQLiteAsyncConnection _dbAsync;
private static readonly object objLock = new(); private static readonly object objLock = new();
public readonly string _configDB = "guiNDB.db";
public SqliteHelper() public SQLiteHelper()
{ {
_connstr = Utils.GetConfigPath(Global.ConfigDB); _connstr = Utils.GetConfigPath(_configDB);
_db = new SQLiteConnection(_connstr, false); _db = new SQLiteConnection(_connstr, false);
_dbAsync = new SQLiteAsyncConnection(_connstr, false); _dbAsync = new SQLiteAsyncConnection(_connstr, false);
} }
@@ -50,7 +51,7 @@ namespace v2rayN.Base
} }
} }
public async Task<int> Replacesync(object model) public async Task<int> ReplaceAsync(object model)
{ {
return await _dbAsync.InsertOrReplaceAsync(model); return await _dbAsync.InsertOrReplaceAsync(model);
} }

View File

@@ -1,9 +1,8 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO;
namespace v2rayN.Base namespace ServiceLib.Common
{ {
internal static class StringEx public static class StringEx
{ {
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value) public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{ {
@@ -80,5 +79,15 @@ namespace v2rayN.Base
return char.ToUpper(value[0]) + value.Substring(1); return char.ToUpper(value[0]) + value.Substring(1);
} }
public static string AppendQuotes(this string value)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
return $"\"{value}\"";
}
} }
} }

View File

@@ -0,0 +1,58 @@
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace ServiceLib.Common
{
public class YamlUtils
{
#region YAML
/// <summary>
/// 反序列化成对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="str"></param>
/// <returns></returns>
public static T FromYaml<T>(string str)
{
var deserializer = new DeserializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.Build();
try
{
T obj = deserializer.Deserialize<T>(str);
return obj;
}
catch (Exception ex)
{
Logging.SaveLog("FromYaml", ex);
return deserializer.Deserialize<T>("");
}
}
/// <summary>
/// 序列化
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToYaml(Object obj)
{
var serializer = new SerializerBuilder()
.WithNamingConvention(HyphenatedNamingConvention.Instance)
.Build();
string result = string.Empty;
try
{
result = serializer.Serialize(obj);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
return result;
}
#endregion YAML
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Enums
{ {
public enum EConfigType public enum EConfigType
{ {
@@ -8,6 +8,9 @@
Socks = 4, Socks = 4,
VLESS = 5, VLESS = 5,
Trojan = 6, Trojan = 6,
Hysteria2 = 7 Hysteria2 = 7,
Tuic = 8,
Wireguard = 9,
Http = 10
} }
} }

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Enums
{ {
public enum ECoreType public enum ECoreType
{ {
@@ -8,6 +8,7 @@
v2fly_v5 = 4, v2fly_v5 = 4,
clash = 11, clash = 11,
clash_meta = 12, clash_meta = 12,
mihomo = 13,
hysteria = 21, hysteria = 21,
naiveproxy = 22, naiveproxy = 22,
tuic = 23, tuic = 23,

View File

@@ -0,0 +1,9 @@
namespace ServiceLib.Enums
{
public enum EGirdOrientation
{
Horizontal,
Vertical,
Tab,
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Enums
{ {
public enum EGlobalHotkey public enum EGlobalHotkey
{ {

View File

@@ -0,0 +1,14 @@
namespace ServiceLib.Enums
{
public enum EInboundProtocol
{
socks = 0,
http,
socks2,
http2,
pac,
api,
api2,
speedtest = 21
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Enums
{ {
public enum EMove public enum EMove
{ {

View File

@@ -0,0 +1,10 @@
namespace ServiceLib.Enums
{
public enum ERuleMode
{
Rule = 0,
Global = 1,
Direct = 2,
Unchanged = 3
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Enums
{ {
public enum EServerColName public enum EServerColName
{ {
@@ -7,7 +7,6 @@
remarks, remarks,
address, address,
port, port,
security,
network, network,
streamSecurity, streamSecurity,
subRemarks, subRemarks,

View File

@@ -1,8 +1,7 @@
namespace v2rayN.Mode namespace ServiceLib.Enums
{ {
public enum ESpeedActionType public enum ESpeedActionType
{ {
Ping,
Tcping, Tcping,
Realping, Realping,
Speedtest, Speedtest,

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Enums
{ {
public enum ESysProxyType public enum ESysProxyType
{ {

View File

@@ -0,0 +1,15 @@
namespace ServiceLib.Enums
{
public enum ETransport
{
tcp,
kcp,
ws,
httpupgrade,
splithttp,
h2,
http,
quic,
grpc
}
}

View File

@@ -0,0 +1,45 @@
namespace ServiceLib.Enums
{
public enum EViewAction
{
CloseWindow,
ShowYesNo,
SaveFileDialog,
AddBatchRoutingRulesYesNo,
AdjustMainLvColWidth,
UpdateSysProxy,
SetClipboardData,
AddServerViaClipboard,
ImportRulesFromClipboard,
ProfilesFocus,
ShareSub,
ShareServer,
ShowHideWindow,
ScanScreenTask,
Shutdown,
BrowseServer,
ImportRulesFromFile,
SubEditWindow,
RoutingRuleSettingWindow,
RoutingRuleDetailsWindow,
AddServerWindow,
AddServer2Window,
DNSSettingWindow,
RoutingSettingWindow,
OptionSettingWindow,
GlobalHotkeySettingWindow,
SubSettingWindow,
DispatcherSpeedTest,
DispatcherRefreshConnections,
DispatcherRefreshProxyGroups,
DispatcherProxiesDelayTest,
DispatcherStatistics,
DispatcherServerAvailability,
DispatcherReload,
DispatcherRefreshServersBiz,
DispatcherRefreshIcon,
DispatcherCheckUpdate,
DispatcherCheckUpdateFinished,
DispatcherShowMsg,
}
}

View File

@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ReactiveUI />
</Weavers>

201
v2rayN/ServiceLib/Global.cs Normal file
View File

@@ -0,0 +1,201 @@
namespace ServiceLib
{
public class Global
{
#region const
public const string AppName = "v2rayN";
public const string GithubUrl = "https://github.com";
public const string GithubApiUrl = "https://api.github.com/repos";
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
public const string SagerNetCoreUrl = "https://github.com/SagerNet/v2ray-core/releases";
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
public const string ClashCoreUrl = "https://github.com/Dreamacro/clash/releases";
public const string ClashMetaCoreUrl = "https://github.com/MetaCubeX/Clash.Meta/releases";
public const string MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
public const string SingboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json";
public const string CoreConfigFileName = "config.json";
public const string CorePreConfigFileName = "configPre.json";
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
public const string ClashMixinConfigFileName = "Mixin.yaml";
public const string V2raySampleClient = "ServiceLib.Sample.SampleClientConfig";
public const string SingboxSampleClient = "ServiceLib.Sample.SingboxSampleClientConfig";
public const string V2raySampleHttpRequestFileName = "ServiceLib.Sample.SampleHttpRequest";
public const string V2raySampleHttpResponseFileName = "ServiceLib.Sample.SampleHttpResponse";
public const string V2raySampleInbound = "ServiceLib.Sample.SampleInbound";
public const string V2raySampleOutbound = "ServiceLib.Sample.SampleOutbound";
public const string SingboxSampleOutbound = "ServiceLib.Sample.SingboxSampleOutbound";
public const string CustomRoutingFileName = "ServiceLib.Sample.custom_routing_";
public const string TunSingboxDNSFileName = "ServiceLib.Sample.tun_singbox_dns";
public const string TunSingboxInboundFileName = "ServiceLib.Sample.tun_singbox_inbound";
public const string TunSingboxRulesFileName = "ServiceLib.Sample.tun_singbox_rules";
public const string DNSV2rayNormalFileName = "ServiceLib.Sample.dns_v2ray_normal";
public const string DNSSingboxNormalFileName = "ServiceLib.Sample.dns_singbox_normal";
public const string ClashMixinYaml = "ServiceLib.Sample.clash_mixin_yaml";
public const string ClashTunYaml = "ServiceLib.Sample.clash_tun_yaml";
public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp";
public const string TcpHeaderHttp = "http";
public const string None = "none";
public const string ProxyTag = "proxy";
public const string DirectTag = "direct";
public const string BlockTag = "block";
public const string StreamSecurity = "tls";
public const string StreamSecurityReality = "reality";
public const string Loopback = "127.0.0.1";
public const string InboundAPIProtocol = "dokodemo-door";
public const string HttpProtocol = "http://";
public const string HttpsProtocol = "https://";
public const string SocksProtocol = "socks://";
public const string UserEMail = "t@t.tt";
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
public const string AutoRunName = "v2rayNAutoRun";
public const string CustomIconName = "v2rayN.ico";
public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
public const string RoutingRuleComma = "<COMMA>";
public const string GrpcGunMode = "gun";
public const string GrpcMultiMode = "multi";
public const int MaxPort = 65536;
public const string CommandClearMsg = "CommandClearMsg";
public const string CommandSendMsgView = "CommandSendMsgView";
public const string CommandSendSnackMsg = "CommandSendSnackMsg";
public const string CommandStopSpeedTest = "CommandStopSpeedTest";
public const string CommandRefreshProfiles = "CommandRefreshProfiles";
public const string DelayUnit = "";
public const string SpeedUnit = "";
public const int MinFontSize = 10;
public const string RebootAs = "rebootas";
public static readonly List<string> IEProxyProtocols = new() {
"{ip}:{http_port}",
"socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
""
};
public static readonly List<string> SubConvertUrls = new List<string> {
@"https://sub.xeton.dev/sub?url={0}",
@"https://api.dler.io/sub?url={0}",
@"http://127.0.0.1:25500/sub?url={0}",
""
};
public static readonly List<string> SubConvertConfig = new List<string> {
@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
};
public static readonly List<string> SubConvertTargets = new List<string> {
"",
"mixed",
"v2ray",
"clash",
"ss",
};
public static readonly List<string> SpeedTestUrls = new() {
@"https://speed.cloudflare.com/__down?bytes=100000000",
@"https://speed.cloudflare.com/__down?bytes=10000000",
@"http://cachefly.cachefly.net/50mb.test",
@"http://cachefly.cachefly.net/10mb.test"
};
public static readonly List<string> SpeedPingTestUrls = new() {
@"https://www.google.com/generate_204",
@"https://www.gstatic.com/generate_204",
@"https://www.apple.com/library/test/success.html",
@"http://www.msftconnecttest.com/connecttest.txt",
};
public static readonly Dictionary<string, string> UserAgentTexts = new()
{
{"chrome","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36" },
{"firefox","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" },
{"safari","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15" },
{"edge","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70" },
{"none",""}
};
public const string Hysteria2ProtocolShare = "hy2://";
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
{
{EConfigType.VMess,"vmess://"},
{EConfigType.Shadowsocks,"ss://"},
{EConfigType.Socks,"socks://"},
{EConfigType.VLESS,"vless://"},
{EConfigType.Trojan,"trojan://"},
{EConfigType.Hysteria2,"hysteria2://"},
{EConfigType.Tuic,"tuic://"},
{EConfigType.Wireguard,"wireguard://"}
};
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
{
{EConfigType.VMess,"vmess"},
{EConfigType.Shadowsocks,"shadowsocks"},
{EConfigType.Socks,"socks"},
{EConfigType.Http,"http"},
{EConfigType.VLESS,"vless"},
{EConfigType.Trojan,"trojan"},
{EConfigType.Hysteria2,"hysteria2"},
{EConfigType.Tuic,"tuic"},
{EConfigType.Wireguard,"wireguard"}
};
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
public static readonly List<string> SsSecuritiesInSagerNet = 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> SsSecuritiesInXray = 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> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "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", "sing_box" };
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
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> AllowInsecure = new() { "true", "false", "" };
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
public static readonly List<string> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" };
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"];
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"];
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" };
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" };
public static readonly List<string> notAllowTestType = new List<string> { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" };
#endregion const
}
}

View File

@@ -0,0 +1,9 @@
global using ServiceLib.Base;
global using ServiceLib.Common;
global using ServiceLib.Enums;
global using ServiceLib.Handler;
global using ServiceLib.Handler.CoreConfig;
global using ServiceLib.Handler.Fmt;
global using ServiceLib.Handler.Statistics;
global using ServiceLib.Models;
global using ServiceLib.Resx;

View File

@@ -0,0 +1,206 @@
using static ServiceLib.Models.ClashProxies;
namespace ServiceLib.Handler
{
public sealed class ClashApiHandler
{
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
public static ClashApiHandler Instance => instance.Value;
private Dictionary<String, ProxiesItem>? _proxies;
public Dictionary<string, object> ProfileContent { get; set; }
public void GetClashProxies(Config config, Action<ClashProxies, ClashProviders> update)
{
Task.Run(() => GetClashProxiesAsync(config, update));
}
private async Task GetClashProxiesAsync(Config config, Action<ClashProxies, ClashProviders> update)
{
for (var i = 0; i < 5; i++)
{
var url = $"{GetApiUrl()}/proxies";
var result = await HttpClientHelper.Instance.TryGetAsync(url);
var clashProxies = JsonUtils.Deserialize<ClashProxies>(result);
var url2 = $"{GetApiUrl()}/providers/proxies";
var result2 = await HttpClientHelper.Instance.TryGetAsync(url2);
var clashProviders = JsonUtils.Deserialize<ClashProviders>(result2);
if (clashProxies != null || clashProviders != null)
{
_proxies = clashProxies?.proxies;
update(clashProxies, clashProviders);
return;
}
Task.Delay(5000).Wait();
}
update(null, null);
}
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> update)
{
Task.Run(() =>
{
if (blAll)
{
for (int i = 0; i < 5; i++)
{
if (_proxies != null)
{
break;
}
Task.Delay(5000).Wait();
}
if (_proxies == null)
{
return;
}
lstProxy = new List<ClashProxyModel>();
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies)
{
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
{
continue;
}
lstProxy.Add(new ClashProxyModel()
{
name = kv.Value.name,
type = kv.Value.type.ToLower(),
});
}
}
if (lstProxy == null)
{
return;
}
var urlBase = $"{GetApiUrl()}/proxies";
urlBase += @"/{0}/delay?timeout=10000&url=" + LazyConfig.Instance.Config.speedTestItem.speedPingTestUrl;
List<Task> tasks = new List<Task>();
foreach (var it in lstProxy)
{
if (Global.notAllowTestType.Contains(it.type.ToLower()))
{
continue;
}
var name = it.name;
var url = string.Format(urlBase, name);
tasks.Add(Task.Run(async () =>
{
var result = await HttpClientHelper.Instance.TryGetAsync(url);
update(it, result);
}));
}
Task.WaitAll(tasks.ToArray());
Task.Delay(1000).Wait();
update(null, "");
});
}
public List<ProxiesItem>? GetClashProxyGroups()
{
try
{
var fileContent = ProfileContent;
if (fileContent is null || fileContent?.ContainsKey("proxy-groups") == false)
{
return null;
}
return JsonUtils.Deserialize<List<ProxiesItem>>(JsonUtils.Serialize(fileContent["proxy-groups"]));
}
catch (Exception ex)
{
Logging.SaveLog("GetClashProxyGroups", ex);
return null;
}
}
public async void ClashSetActiveProxy(string name, string nameNode)
{
try
{
var url = $"{GetApiUrl()}/proxies/{name}";
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("name", nameNode);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
public void ClashConfigUpdate(Dictionary<string, string> headers)
{
Task.Run(async () =>
{
if (_proxies == null)
{
return;
}
var urlBase = $"{GetApiUrl()}/configs";
await HttpClientHelper.Instance.PatchAsync(urlBase, headers);
});
}
public async void ClashConfigReload(string filePath)
{
ClashConnectionClose("");
try
{
var url = $"{GetApiUrl()}/configs?force=true";
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("path", filePath);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
public void GetClashConnections(Config config, Action<ClashConnections> update)
{
Task.Run(() => GetClashConnectionsAsync(config, update));
}
private async Task GetClashConnectionsAsync(Config config, Action<ClashConnections> update)
{
try
{
var url = $"{GetApiUrl()}/connections";
var result = await HttpClientHelper.Instance.TryGetAsync(url);
var clashConnections = JsonUtils.Deserialize<ClashConnections>(result);
update(clashConnections);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
public async void ClashConnectionClose(string id)
{
try
{
var url = $"{GetApiUrl()}/connections/{id}";
await HttpClientHelper.Instance.DeleteAsync(url);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
private string GetApiUrl()
{
return $"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
}
}
}

View File

@@ -0,0 +1,265 @@
namespace ServiceLib.Handler.CoreConfig
{
/// <summary>
/// Core configuration file processing class
/// </summary>
public class CoreConfigClash
{
private Config _config;
public CoreConfigClash(Config config)
{
_config = config;
}
/// <summary>
/// 生成配置文件
/// </summary>
/// <param name="node"></param>
/// <param name="fileName"></param>
/// <param name="msg"></param>
/// <returns></returns>
public int GenerateClientCustomConfig(ProfileItem node, string? fileName, out string msg)
{
if (node == null || fileName is null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
msg = ResUI.InitialConfiguration;
try
{
if (node == null)
{
msg = ResUI.CheckServerSettings;
return -1;
}
if (File.Exists(fileName))
{
File.Delete(fileName);
}
string addressFileName = node.address;
if (string.IsNullOrEmpty(addressFileName))
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
}
if (!File.Exists(addressFileName))
{
addressFileName = Path.Combine(Utils.GetConfigPath(), addressFileName);
}
if (!File.Exists(addressFileName))
{
msg = ResUI.FailedReadConfiguration + "1";
return -1;
}
string tagYamlStr1 = "!<str>";
string tagYamlStr2 = "__strn__";
string tagYamlStr3 = "!!str";
var txtFile = File.ReadAllText(addressFileName);
txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2);
var fileContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
if (fileContent == null)
{
msg = ResUI.FailedConversionConfiguration;
return -1;
}
//port
fileContent["port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
//socks-port
fileContent["socks-port"] = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks);
//log-level
fileContent["log-level"] = GetLogLevel(_config.coreBasicItem.loglevel);
//external-controller
fileContent["external-controller"] = $"{Global.Loopback}:{LazyConfig.Instance.StatePort2}";
//allow-lan
if (_config.inbound[0].allowLANConn)
{
fileContent["allow-lan"] = "true";
fileContent["bind-address"] = "*";
}
else
{
fileContent["allow-lan"] = "false";
}
//ipv6
fileContent["ipv6"] = _config.clashUIItem.enableIPv6;
//mode
if (!fileContent.ContainsKey("mode"))
{
fileContent["mode"] = ERuleMode.Rule.ToString().ToLower();
}
else
{
if (_config.clashUIItem.ruleMode != ERuleMode.Unchanged)
{
fileContent["mode"] = _config.clashUIItem.ruleMode.ToString().ToLower();
}
}
//enable tun mode
if (_config.tunModeItem.enableTun)
{
string tun = Utils.GetEmbedText(Global.ClashTunYaml);
if (!string.IsNullOrEmpty(tun))
{
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
if (tunContent != null)
fileContent["tun"] = tunContent["tun"];
}
}
//Mixin
try
{
MixinContent(fileContent, node);
}
catch (Exception ex)
{
Logging.SaveLog("GenerateClientConfigClash-Mixin", ex);
}
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
File.WriteAllText(fileName, txtFileNew);
//check again
if (!File.Exists(fileName))
{
msg = ResUI.FailedReadConfiguration + "2";
return -1;
}
ClashApiHandler.Instance.ProfileContent = fileContent;
msg = string.Format(ResUI.SuccessfulConfiguration, $"{node.GetSummary()}");
}
catch (Exception ex)
{
Logging.SaveLog("GenerateClientConfigClash", ex);
msg = ResUI.FailedGenDefaultConfiguration;
return -1;
}
return 0;
}
private void MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
{
//if (!_config.clashUIItem.enableMixinContent)
//{
// return;
//}
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
if (!File.Exists(path))
{
return;
}
var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
if (mixinContent == null)
{
return;
}
foreach (var item in mixinContent)
{
if (!_config.tunModeItem.enableTun && item.Key == "tun")
{
continue;
}
if (item.Key.StartsWith("prepend-")
|| item.Key.StartsWith("append-")
|| item.Key.StartsWith("removed-"))
{
ModifyContentMerge(fileContent, item.Key, item.Value);
}
else
{
fileContent[item.Key] = item.Value;
}
}
return;
}
private void ModifyContentMerge(Dictionary<string, object> fileContent, string key, object value)
{
bool blPrepend = false;
bool blRemoved = false;
if (key.StartsWith("prepend-"))
{
blPrepend = true;
key = key.Replace("prepend-", "");
}
else if (key.StartsWith("append-"))
{
blPrepend = false;
key = key.Replace("append-", "");
}
else if (key.StartsWith("removed-"))
{
blRemoved = true;
key = key.Replace("removed-", "");
}
else
{
return;
}
if (!blRemoved && !fileContent.ContainsKey(key))
{
fileContent.Add(key, value);
return;
}
var lstOri = (List<object>)fileContent[key];
var lstValue = (List<object>)value;
if (blRemoved)
{
foreach (var item in lstValue)
{
lstOri.RemoveAll(t => t.ToString().StartsWith(item.ToString()));
}
return;
}
if (blPrepend)
{
lstValue.Reverse();
foreach (var item in lstValue)
{
lstOri.Insert(0, item);
}
}
else
{
foreach (var item in lstValue)
{
lstOri.Add(item);
}
}
}
private string GetLogLevel(string level)
{
if (level == "none")
{
return "silent";
}
else
{
return level;
}
}
}
}

View File

@@ -1,13 +1,9 @@
using System.IO; namespace ServiceLib.Handler.CoreConfig
using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Handler
{ {
/// <summary> /// <summary>
/// Core configuration file processing class /// Core configuration file processing class
/// </summary> /// </summary>
internal class CoreConfigHandler public class CoreConfigHandler
{ {
public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content) public static int GenerateClientConfig(ProfileItem node, string? fileName, out string msg, out string content)
{ {
@@ -19,14 +15,27 @@ namespace v2rayN.Handler
msg = ResUI.CheckServerSettings; msg = ResUI.CheckServerSettings;
return -1; return -1;
} }
var config = LazyConfig.Instance.GetConfig(); var config = LazyConfig.Instance.Config;
msg = ResUI.InitialConfiguration; msg = ResUI.InitialConfiguration;
if (node.configType == EConfigType.Custom) if (node.configType == EConfigType.Custom)
{ {
return GenerateClientCustomConfig(node, fileName, out msg); if (node.coreType is ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
{
var configGenClash = new CoreConfigClash(config);
return configGenClash.GenerateClientCustomConfig(node, fileName, out msg);
}
if (node.coreType is ECoreType.sing_box)
{
var configGenSingbox = new CoreConfigSingbox(config);
return configGenSingbox.GenerateClientCustomConfig(node, fileName, out msg);
}
else
{
return GenerateClientCustomConfig(node, fileName, out msg);
}
} }
else if (config.tunModeItem.enableTun || LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box) else if (LazyConfig.Instance.GetCoreType(node, node.configType) == ECoreType.sing_box)
{ {
var configGenSingbox = new CoreConfigSingbox(config); var configGenSingbox = new CoreConfigSingbox(config);
if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0) if (configGenSingbox.GenerateClientConfigContent(node, out SingboxConfig? singboxConfig, out msg) != 0)
@@ -35,11 +44,11 @@ namespace v2rayN.Handler
} }
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
content = Utils.ToJson(singboxConfig); content = JsonUtils.Serialize(singboxConfig);
} }
else else
{ {
Utils.ToJsonFile(singboxConfig, fileName, false); JsonUtils.ToFile(singboxConfig, fileName, false);
} }
} }
else else
@@ -51,17 +60,17 @@ namespace v2rayN.Handler
} }
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
content = Utils.ToJson(v2rayConfig); content = JsonUtils.Serialize(v2rayConfig);
} }
else else
{ {
Utils.ToJsonFile(v2rayConfig, fileName, false); JsonUtils.ToFile(v2rayConfig, fileName, false);
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog("GenerateClientConfig", ex); Logging.SaveLog("GenerateClientConfig", ex);
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
return -1; return -1;
} }
@@ -104,55 +113,59 @@ namespace v2rayN.Handler
return -1; return -1;
} }
//overwrite port
if (node.preSocksPort <= 0)
{
var fileContent = File.ReadAllLines(fileName).ToList();
var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
switch (coreType)
{
case ECoreType.v2fly:
case ECoreType.SagerNet:
case ECoreType.Xray:
case ECoreType.v2fly_v5:
break;
case ECoreType.clash:
case ECoreType.clash_meta:
//remove the original
var indexPort = fileContent.FindIndex(t => t.Contains("port:"));
if (indexPort >= 0)
{
fileContent.RemoveAt(indexPort);
}
indexPort = fileContent.FindIndex(t => t.Contains("socks-port:"));
if (indexPort >= 0)
{
fileContent.RemoveAt(indexPort);
}
fileContent.Add($"port: {LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}");
fileContent.Add($"socks-port: {LazyConfig.Instance.GetLocalPort(Global.InboundSocks)}");
break;
}
File.WriteAllLines(fileName, fileContent);
}
msg = string.Format(ResUI.SuccessfulConfiguration, ""); msg = string.Format(ResUI.SuccessfulConfiguration, "");
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog("GenerateClientCustomConfig", ex); Logging.SaveLog("GenerateClientCustomConfig", ex);
msg = ResUI.FailedGenDefaultConfiguration; msg = ResUI.FailedGenDefaultConfiguration;
return -1; return -1;
} }
return 0; return 0;
} }
public static string GenerateClientSpeedtestConfigString(Config config, List<ServerTestItem> selecteds, out string msg) public static int GenerateClientSpeedtestConfig(Config config, string fileName, List<ServerTestItem> selecteds, ECoreType coreType, out string msg)
{ {
var coreConfigV2ray = new CoreConfigV2ray(config); if (coreType == ECoreType.sing_box)
return coreConfigV2ray.GenerateClientSpeedtestConfigString(selecteds, out msg); {
if (new CoreConfigSingbox(config).GenerateClientSpeedtestConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
{
return -1;
}
JsonUtils.ToFile(singboxConfig, fileName, false);
}
else
{
if (new CoreConfigV2ray(config).GenerateClientSpeedtestConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
{
return -1;
}
JsonUtils.ToFile(v2rayConfig, fileName, false);
}
return 0;
}
public static int GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType, out string msg)
{
msg = ResUI.CheckServerSettings;
if (coreType == ECoreType.sing_box)
{
if (new CoreConfigSingbox(config).GenerateClientMultipleLoadConfig(selecteds, out SingboxConfig? singboxConfig, out msg) != 0)
{
return -1;
}
JsonUtils.ToFile(singboxConfig, fileName, false);
}
else if (coreType == ECoreType.Xray)
{
if (new CoreConfigV2ray(config).GenerateClientMultipleLoadConfig(selecteds, out V2rayConfig? v2rayConfig, out msg) != 0)
{
return -1;
}
JsonUtils.ToFile(v2rayConfig, fileName, false);
}
return 0;
} }
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,12 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Reactive.Linq;
using System.Text; using System.Text;
using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Handler namespace ServiceLib.Handler
{ {
/// <summary> /// <summary>
/// Core process processing class /// Core process processing class
/// </summary> /// </summary>
internal class CoreHandler public class CoreHandler
{ {
private Config _config; private Config _config;
private Process? _process; private Process? _process;
@@ -26,19 +22,19 @@ namespace v2rayN.Handler
Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("xray.location.asset", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
} }
public void LoadCore() public void LoadCore(ProfileItem? node)
{ {
var node = ConfigHandler.GetDefaultServer(ref _config);
if (node == null) if (node == null)
{ {
ShowMsg(false, ResUI.CheckServerSettings); ShowMsg(false, ResUI.CheckServerSettings);
return; return;
} }
string fileName = Utils.GetConfigPath(Global.coreConfigFileName); string fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
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);
return;
} }
else else
{ {
@@ -48,37 +44,38 @@ namespace v2rayN.Handler
CoreStart(node); CoreStart(node);
//In tun mode, do a delay check and restart the core //In tun mode, do a delay check and restart the core
if (_config.tunModeItem.enableTun) //if (_config.tunModeItem.enableTun)
{ //{
Observable.Range(1, 1) // Observable.Range(1, 1)
.Delay(TimeSpan.FromSeconds(15)) // .Delay(TimeSpan.FromSeconds(15))
.Subscribe(x => // .Subscribe(x =>
{ // {
{ // {
if (_process == null || _process.HasExited) // if (_process == null || _process.HasExited)
{ // {
CoreStart(node); // CoreStart(node);
ShowMsg(false, "Tun mode restart the core once"); // ShowMsg(false, "Tun mode restart the core once");
Utils.SaveLog("Tun mode restart the core once"); // Logging.SaveLog("Tun mode restart the core once");
} // }
} // }
}); // });
} //}
} }
} }
public int LoadCoreConfigString(List<ServerTestItem> _selecteds) public int LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
{ {
int pid = -1; int pid = -1;
string configStr = CoreConfigHandler.GenerateClientSpeedtestConfigString(_config, _selecteds, out string msg); var coreType = selecteds.Exists(t => t.configType == EConfigType.Hysteria2 || t.configType == EConfigType.Tuic || t.configType == EConfigType.Wireguard) ? ECoreType.sing_box : ECoreType.Xray;
if (configStr == "") string configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
if (CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType, out string msg) != 0)
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
} }
else else
{ {
ShowMsg(false, msg); ShowMsg(false, msg);
pid = CoreStartViaString(configStr); pid = CoreStartSpeedtest(configPath, coreType);
} }
return pid; return pid;
} }
@@ -106,8 +103,8 @@ namespace v2rayN.Handler
if (!hasProc) if (!hasProc)
{ {
var coreInfos = LazyConfig.Instance.GetCoreInfos(); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfos) foreach (var it in coreInfo)
{ {
if (it.coreType == ECoreType.v2rayN) if (it.coreType == ECoreType.v2rayN)
{ {
@@ -115,11 +112,11 @@ namespace v2rayN.Handler
} }
foreach (string vName in it.coreExes) foreach (string vName in it.coreExes)
{ {
Process[] existing = Process.GetProcessesByName(vName); var 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, it.coreType)}.exe") if (path == Utils.GetExeName(Utils.GetBinPath(vName, it.coreType.ToString())))
{ {
KillProcess(p); KillProcess(p);
} }
@@ -130,7 +127,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }
@@ -138,22 +135,24 @@ namespace v2rayN.Handler
{ {
try try
{ {
Process _p = Process.GetProcessById(pid); var _p = Process.GetProcessById(pid);
KillProcess(_p); KillProcess(_p);
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }
private string CoreFindexe(CoreInfo coreInfo) #region Private
private string CoreFindExe(CoreInfo coreInfo)
{ {
string fileName = string.Empty; string fileName = string.Empty;
foreach (string name in coreInfo.coreExes) foreach (string name in coreInfo.coreExes)
{ {
string vName = $"{name}.exe"; string vName = Utils.GetExeName(name);
vName = Utils.GetBinPath(vName, coreInfo.coreType); vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
if (File.Exists(vName)) if (File.Exists(vName))
{ {
fileName = vName; fileName = vName;
@@ -162,8 +161,8 @@ 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.ToString()), string.Join(", ", coreInfo.coreExes.ToArray()), coreInfo.coreUrl);
Utils.SaveLog(msg); Logging.SaveLog(msg);
ShowMsg(false, msg); ShowMsg(false, msg);
} }
return fileName; return fileName;
@@ -171,44 +170,65 @@ namespace v2rayN.Handler
private void CoreStart(ProfileItem node) private void CoreStart(ProfileItem node)
{ {
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))); ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ECoreType coreType; //ECoreType coreType;
if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun) //if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
{ //{
coreType = ECoreType.sing_box; // coreType = ECoreType.sing_box;
} //}
else //else
{ //{
coreType = LazyConfig.Instance.GetCoreType(node, node.configType); // coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
} //}
var coreInfo = LazyConfig.Instance.GetCoreInfo(coreType); var coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
_config.runningCoreType = coreType;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.configType != EConfigType.Custom || node.displayLog; var displayLog = node.configType != EConfigType.Custom || node.displayLog;
var proc = RunProcess(node, coreInfo, "", displayLog, ShowMsg); var proc = RunProcess(node, coreInfo, "", displayLog);
if (proc is null) if (proc is null)
{ {
return; return;
} }
_process = proc; _process = proc;
//start a socks service //start a pre service
if (_process != null && !_process.HasExited) if (_process != null && !_process.HasExited)
{ {
if ((node.configType == EConfigType.Custom && node.preSocksPort > 0)) ProfileItem? itemSocks = null;
var preCoreType = ECoreType.sing_box;
if (node.configType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.tunModeItem.enableTun)
{ {
var itemSocks = new ProfileItem() itemSocks = new ProfileItem()
{ {
coreType = ECoreType.sing_box, coreType = preCoreType,
configType = EConfigType.Socks, configType = EConfigType.Socks,
address = Global.Loopback, address = Global.Loopback,
port = node.preSocksPort sni = node.address, //Tun2SocksAddress
port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.socks)
}; };
string fileName2 = Utils.GetConfigPath(Global.corePreConfigFileName); }
else if ((node.configType == EConfigType.Custom && node.preSocksPort > 0))
{
preCoreType = _config.tunModeItem.enableTun ? ECoreType.sing_box : ECoreType.Xray;
itemSocks = new ProfileItem()
{
coreType = preCoreType,
configType = EConfigType.Socks,
address = Global.Loopback,
port = node.preSocksPort.Value,
};
_config.runningCoreType = preCoreType;
}
if (itemSocks != null)
{
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0) if (CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2, out string msg2, out string configStr) == 0)
{ {
var coreInfo2 = LazyConfig.Instance.GetCoreInfo(ECoreType.sing_box); var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = RunProcess(node, coreInfo2, $" -c {Global.corePreConfigFileName}", true, ShowMsg); var proc2 = RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
if (proc2 is not null) if (proc2 is not null)
{ {
_processPre = proc2; _processPre = proc2;
@@ -218,91 +238,52 @@ namespace v2rayN.Handler
} }
} }
private int CoreStartViaString(string configStr) private int CoreStartSpeedtest(string configPath, ECoreType coreType)
{ {
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))); ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try try
{ {
var coreInfo = LazyConfig.Instance.GetCoreInfo(ECoreType.Xray); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
string fileName = CoreFindexe(coreInfo); var proc = RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
if (fileName == "") return -1; if (proc is null)
Process p = new()
{ {
StartInfo = new ProcessStartInfo return -1;
{
FileName = fileName,
Arguments = "-config stdin:",
WorkingDirectory = Utils.GetConfigPath(),
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
}
};
p.OutputDataReceived += (sender, e) =>
{
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;
ShowMsg(false, msg);
}
};
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.StandardInput.Write(configStr);
p.StandardInput.Close();
if (p.WaitForExit(1000))
{
throw new Exception(p.StandardError.ReadToEnd());
} }
Global.processJob.AddProcess(p.Handle); return proc.Id;
return p.Id;
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
string msg = ex.Message; string msg = ex.Message;
ShowMsg(false, msg); ShowMsg(false, msg);
return -1; return -1;
} }
} }
private void ShowMsg(bool updateToTrayTooltip, string msg) private void ShowMsg(bool notify, string msg)
{ {
_updateFunc(updateToTrayTooltip, msg); _updateFunc(notify, msg);
} }
#endregion Private
#region Process #region Process
private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog, Action<bool, string> update) private Process? RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
{ {
try try
{ {
string fileName = CoreFindexe(coreInfo); string fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
return null; return null;
} }
Process proc = new() Process proc = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new()
{ {
FileName = fileName, FileName = fileName,
Arguments = string.Format(coreInfo.arguments, configPath), Arguments = string.Format(coreInfo.arguments, configPath),
@@ -315,22 +296,29 @@ namespace v2rayN.Handler
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null, StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
} }
}; };
var startUpErrorMessage = new StringBuilder();
var startUpSuccessful = false;
if (displayLog) if (displayLog)
{ {
proc.OutputDataReceived += (sender, e) => proc.OutputDataReceived += (sender, e) =>
{ {
if (!string.IsNullOrEmpty(e.Data)) if (!Utils.IsNullOrEmpty(e.Data))
{ {
string msg = e.Data + Environment.NewLine; string msg = e.Data + Environment.NewLine;
update(false, msg); ShowMsg(false, msg);
} }
}; };
proc.ErrorDataReceived += (sender, e) => proc.ErrorDataReceived += (sender, e) =>
{ {
if (!string.IsNullOrEmpty(e.Data)) if (!Utils.IsNullOrEmpty(e.Data))
{ {
string msg = e.Data + Environment.NewLine; string msg = e.Data + Environment.NewLine;
update(false, msg); ShowMsg(false, msg);
if (!startUpSuccessful)
{
startUpErrorMessage.Append(msg);
}
} }
}; };
} }
@@ -343,36 +331,45 @@ namespace v2rayN.Handler
if (proc.WaitForExit(1000)) if (proc.WaitForExit(1000))
{ {
throw new Exception(displayLog ? proc.StandardError.ReadToEnd() : "启动进程失败并退出 (Failed to start the process and exited)"); proc.CancelErrorRead();
throw new Exception(displayLog ? startUpErrorMessage.ToString() : "启动进程失败并退出 (Failed to start the process and exited)");
}
else
{
startUpSuccessful = true;
} }
Global.processJob.AddProcess(proc.Handle); LazyConfig.Instance.AddProcess(proc.Handle);
return proc; return proc;
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
string msg = ex.Message; string msg = ex.Message;
update(true, msg); ShowMsg(true, msg);
return null; return null;
} }
} }
private void KillProcess(Process p) private void KillProcess(Process? proc)
{ {
if (proc is null)
{
return;
}
try try
{ {
p.CloseMainWindow(); proc.Kill();
p.WaitForExit(100); proc.WaitForExit(100);
if (!p.HasExited) if (!proc.HasExited)
{ {
p.Kill(); proc.Kill();
p.WaitForExit(100); proc.WaitForExit(100);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }

View File

@@ -0,0 +1,217 @@
using System.Runtime.Intrinsics.X86;
namespace ServiceLib.Handler
{
public sealed class CoreInfoHandler
{
private static readonly Lazy<CoreInfoHandler> _instance = new(() => new());
private List<CoreInfo>? _coreInfo;
public static CoreInfoHandler Instance => _instance.Value;
public CoreInfoHandler()
{
InitCoreInfo();
}
public CoreInfo? GetCoreInfo(ECoreType coreType)
{
if (_coreInfo == null)
{
InitCoreInfo();
}
return _coreInfo?.FirstOrDefault(t => t.coreType == coreType);
}
public List<CoreInfo> GetCoreInfo()
{
if (_coreInfo == null)
{
InitCoreInfo();
}
return _coreInfo ?? [];
}
private void InitCoreInfo()
{
_coreInfo = [];
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.v2rayN,
coreUrl = Global.NUrl,
coreReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
coreDownloadUrl32 = Global.NUrl + "/download/{0}/v2rayN-32.zip",
coreDownloadUrl64 = Global.NUrl + "/download/{0}/v2rayN.zip",
coreDownloadUrlArm64 = Global.NUrl + "/download/{0}/v2rayN-arm64.zip",
coreDownloadUrlLinux32 = Global.NUrl + "/download/{0}/v2rayN-linux-32.zip",
coreDownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
coreDownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.v2fly,
coreExes = new List<string> { "wv2ray", "v2ray" },
arguments = "",
coreUrl = Global.V2flyCoreUrl,
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "V2Ray",
versionArg = "-version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.SagerNet,
coreExes = new List<string> { "SagerNet", "v2ray" },
arguments = "run",
coreUrl = Global.SagerNetCoreUrl,
coreReleaseApiUrl = Global.SagerNetCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "V2Ray",
versionArg = "version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.v2fly_v5,
coreExes = new List<string> { "v2ray" },
arguments = "run -c config.json -format jsonv5",
coreUrl = Global.V2flyCoreUrl,
coreReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "V2Ray",
versionArg = "version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.Xray,
coreExes = new List<string> { "xray", "wxray" },
arguments = "run {0}",
coreUrl = Global.XrayCoreUrl,
coreReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
coreDownloadUrl32 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-32.zip",
coreDownloadUrl64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
coreDownloadUrlArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
coreDownloadUrlLinux32 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-32.zip",
coreDownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
coreDownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
match = "Xray",
versionArg = "-version",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.clash,
coreExes = new List<string> { "clash-windows-amd64-v3", "clash-windows-amd64", "clash-windows-386", "clash" },
arguments = "-f config.json" + PortableMode(),
coreUrl = Global.ClashCoreUrl,
coreReleaseApiUrl = Global.ClashCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "v",
versionArg = "-v",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.clash_meta,
coreExes = new List<string> { "Clash.Meta-windows-amd64-compatible", "Clash.Meta-windows-amd64", "Clash.Meta-windows-386", "Clash.Meta", "clash" },
arguments = "-f config.json" + PortableMode(),
coreUrl = Global.ClashMetaCoreUrl,
coreReleaseApiUrl = Global.ClashMetaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
match = "v",
versionArg = "-v",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.mihomo,
coreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
arguments = "-f config.json" + PortableMode(),
coreUrl = Global.MihomoCoreUrl,
coreReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
coreDownloadUrl32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-386-{0}.zip",
coreDownloadUrl64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
coreDownloadUrlArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
coreDownloadUrlLinux32 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-386-{0}.gz",
coreDownloadUrlLinux64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
coreDownloadUrlLinuxArm64 = Global.ClashMetaCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
match = "Mihomo",
versionArg = "-v",
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.hysteria,
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
arguments = "",
coreUrl = Global.HysteriaCoreUrl,
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.naiveproxy,
coreExes = new List<string> { "naiveproxy", "naive" },
arguments = "config.json",
coreUrl = Global.NaiveproxyCoreUrl,
redirectInfo = false,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.tuic,
coreExes = new List<string> { "tuic-client", "tuic" },
arguments = "-c config.json",
coreUrl = Global.TuicCoreUrl,
redirectInfo = true,
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.sing_box,
coreExes = new List<string> { "sing-box-client", "sing-box" },
arguments = "run {0} --disable-color",
coreUrl = Global.SingboxCoreUrl,
redirectInfo = true,
coreReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
coreDownloadUrl32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-386.zip",
coreDownloadUrl64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
coreDownloadUrlArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
coreDownloadUrlLinux32 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-386.tar.gz",
coreDownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
coreDownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
match = "sing-box",
versionArg = "version",
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.juicity,
coreExes = new List<string> { "juicity-client", "juicity" },
arguments = "run -c config.json",
coreUrl = Global.JuicityCoreUrl
});
_coreInfo.Add(new CoreInfo
{
coreType = ECoreType.hysteria2,
coreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
arguments = "",
coreUrl = Global.HysteriaCoreUrl,
coreReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
redirectInfo = true,
});
}
private string PortableMode()
{
return $" -d \"{Utils.GetBinPath("")}\"";
}
}
}

View File

@@ -1,18 +1,14 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Net; using System.Net;
using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Sockets; using System.Net.Sockets;
using v2rayN.Base;
using v2rayN.Resx;
namespace v2rayN.Handler namespace ServiceLib.Handler
{ {
/// <summary> /// <summary>
///Download ///Download
/// </summary> /// </summary>
internal class DownloadHandle public class DownloadHandler
{ {
public event EventHandler<ResultEventArgs>? UpdateCompleted; public event EventHandler<ResultEventArgs>? UpdateCompleted;
@@ -34,7 +30,7 @@ namespace v2rayN.Handler
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var progress = new Progress<string>(); var progress = new Progress<string>();
progress.ProgressChanged += (sender, value) => progress.ProgressChanged += (sender, value) =>
@@ -62,11 +58,11 @@ namespace v2rayN.Handler
return 0; return 0;
} }
public async Task DownloadFileAsync(string url, bool blProxy, int downloadTimeout) public async Task DownloadFileAsync(string url, string fileName, bool blProxy, int downloadTimeout)
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
UpdateCompleted?.Invoke(this, new ResultEventArgs(false, $"{ResUI.Downloading} {url}")); UpdateCompleted?.Invoke(this, new ResultEventArgs(false, $"{ResUI.Downloading} {url}"));
var progress = new Progress<double>(); var progress = new Progress<double>();
@@ -78,13 +74,13 @@ namespace v2rayN.Handler
var webProxy = GetWebProxy(blProxy); var webProxy = GetWebProxy(blProxy);
await DownloaderHelper.Instance.DownloadFileAsync(webProxy, await DownloaderHelper.Instance.DownloadFileAsync(webProxy,
url, url,
Utils.GetTempPath(Utils.GetDownloadFileName(url)), fileName,
progress, progress,
downloadTimeout); downloadTimeout);
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex)); Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null) if (ex.InnerException != null)
@@ -96,7 +92,7 @@ namespace v2rayN.Handler
public async Task<string?> UrlRedirectAsync(string url, bool blProxy) public async Task<string?> UrlRedirectAsync(string url, bool blProxy)
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var webRequestHandler = new SocketsHttpHandler var webRequestHandler = new SocketsHttpHandler
{ {
AllowAutoRedirect = false, AllowAutoRedirect = false,
@@ -111,7 +107,7 @@ namespace v2rayN.Handler
} }
else else
{ {
Utils.SaveLog("StatusCode error: " + url); Logging.SaveLog("StatusCode error: " + url);
return null; return null;
} }
} }
@@ -128,7 +124,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex)); Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null) if (ex.InnerException != null)
{ {
@@ -146,7 +142,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex)); Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null) if (ex.InnerException != null)
{ {
@@ -166,7 +162,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex)); Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null) if (ex.InnerException != null)
{ {
@@ -185,7 +181,7 @@ namespace v2rayN.Handler
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy); var webProxy = GetWebProxy(blProxy);
var client = new HttpClient(new SocketsHttpHandler() var client = new HttpClient(new SocketsHttpHandler()
{ {
@@ -212,7 +208,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex)); Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null) if (ex.InnerException != null)
{ {
@@ -230,7 +226,7 @@ namespace v2rayN.Handler
{ {
try try
{ {
Utils.SetSecurityProtocol(LazyConfig.Instance.GetConfig().guiItem.enableSecurityProtocolTls13); Utils.SetSecurityProtocol(LazyConfig.Instance.Config.guiItem.enableSecurityProtocolTls13);
var webProxy = GetWebProxy(blProxy); var webProxy = GetWebProxy(blProxy);
@@ -243,7 +239,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
Error?.Invoke(this, new ErrorEventArgs(ex)); Error?.Invoke(this, new ErrorEventArgs(ex));
if (ex.InnerException != null) if (ex.InnerException != null)
{ {
@@ -264,19 +260,19 @@ namespace v2rayN.Handler
try try
{ {
var config = LazyConfig.Instance.GetConfig(); var config = LazyConfig.Instance.Config;
int responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10); int responseTime = await GetRealPingTime(config.speedTestItem.speedPingTestUrl, webProxy, 10);
return responseTime; return responseTime;
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
return -1; return -1;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
return -1; return -1;
} }
} }
@@ -286,8 +282,6 @@ namespace v2rayN.Handler
int responseTime = -1; int responseTime = -1;
try try
{ {
Stopwatch timer = Stopwatch.StartNew();
using var cts = new CancellationTokenSource(); using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout)); cts.CancelAfter(TimeSpan.FromSeconds(downloadTimeout));
using var client = new HttpClient(new SocketsHttpHandler() using var client = new HttpClient(new SocketsHttpHandler()
@@ -295,13 +289,21 @@ namespace v2rayN.Handler
Proxy = webProxy, Proxy = webProxy,
UseProxy = webProxy != null UseProxy = webProxy != null
}); });
await client.GetAsync(url, cts.Token);
responseTime = timer.Elapsed.Milliseconds; List<int> oneTime = [];
for (int i = 0; i < 2; i++)
{
var timer = Stopwatch.StartNew();
await client.GetAsync(url, cts.Token);
timer.Stop();
oneTime.Add((int)timer.Elapsed.TotalMilliseconds);
await Task.Delay(100);
}
responseTime = oneTime.Where(x => x > 0).OrderBy(x => x).FirstOrDefault();
} }
catch (Exception ex) catch //(Exception ex)
{ {
//Utils.SaveLog(ex.Message, ex); //Utile.SaveLog(ex.Message, ex);
} }
return responseTime; return responseTime;
} }
@@ -312,7 +314,7 @@ namespace v2rayN.Handler
{ {
return null; return null;
} }
var httpPort = LazyConfig.Instance.GetLocalPort(Global.InboundHttp); var httpPort = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
if (!SocketCheck(Global.Loopback, httpPort)) if (!SocketCheck(Global.Loopback, httpPort))
{ {
return null; return null;

View File

@@ -0,0 +1,205 @@
using System.Collections.Specialized;
namespace ServiceLib.Handler.Fmt
{
public class BaseFmt
{
protected static string GetIpv6(string address)
{
if (Utils.IsIpv6(address))
{
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
}
return address; // 如果不是IPv6地址直接返回原地址
}
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
{
if (!Utils.IsNullOrEmpty(item.flow))
{
dicQuery.Add("flow", item.flow);
}
if (!Utils.IsNullOrEmpty(item.streamSecurity))
{
dicQuery.Add("security", item.streamSecurity);
}
else
{
if (securityDef != null)
{
dicQuery.Add("security", securityDef);
}
}
if (!Utils.IsNullOrEmpty(item.sni))
{
dicQuery.Add("sni", item.sni);
}
if (!Utils.IsNullOrEmpty(item.alpn))
{
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
}
if (!Utils.IsNullOrEmpty(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));
}
if (item.allowInsecure.Equals("true"))
{
dicQuery.Add("allowInsecure", "1");
}
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
switch (item.network)
{
case nameof(ETransport.tcp):
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
if (!Utils.IsNullOrEmpty(item.requestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
}
break;
case nameof(ETransport.kcp):
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
if (!Utils.IsNullOrEmpty(item.path))
{
dicQuery.Add("seed", Utils.UrlEncode(item.path));
}
break;
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
if (!Utils.IsNullOrEmpty(item.requestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
}
if (!Utils.IsNullOrEmpty(item.path))
{
dicQuery.Add("path", Utils.UrlEncode(item.path));
}
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http);
if (!Utils.IsNullOrEmpty(item.requestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
}
if (!Utils.IsNullOrEmpty(item.path))
{
dicQuery.Add("path", Utils.UrlEncode(item.path));
}
break;
case nameof(ETransport.quic):
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
dicQuery.Add("key", Utils.UrlEncode(item.path));
break;
case nameof(ETransport.grpc):
if (!Utils.IsNullOrEmpty(item.path))
{
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
if (item.headerType is Global.GrpcGunMode or Global.GrpcMultiMode)
{
dicQuery.Add("mode", Utils.UrlEncode(item.headerType));
}
}
break;
}
return 0;
}
protected static int ResolveStdTransport(NameValueCollection query, ref ProfileItem item)
{
item.flow = query["flow"] ?? "";
item.streamSecurity = query["security"] ?? "";
item.sni = query["sni"] ?? "";
item.alpn = Utils.UrlDecode(query["alpn"] ?? "");
item.fingerprint = Utils.UrlDecode(query["fp"] ?? "");
item.publicKey = Utils.UrlDecode(query["pbk"] ?? "");
item.shortId = Utils.UrlDecode(query["sid"] ?? "");
item.spiderX = Utils.UrlDecode(query["spx"] ?? "");
item.allowInsecure = (query["allowInsecure"] ?? "") == "1" ? "true" : "";
item.network = query["type"] ?? nameof(ETransport.tcp);
switch (item.network)
{
case nameof(ETransport.tcp):
item.headerType = query["headerType"] ?? Global.None;
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
break;
case nameof(ETransport.kcp):
item.headerType = query["headerType"] ?? Global.None;
item.path = Utils.UrlDecode(query["seed"] ?? "");
break;
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
item.path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
item.network = nameof(ETransport.h2);
item.requestHost = Utils.UrlDecode(query["host"] ?? "");
item.path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.quic):
item.headerType = query["headerType"] ?? Global.None;
item.requestHost = query["quicSecurity"] ?? Global.None;
item.path = Utils.UrlDecode(query["key"] ?? "");
break;
case nameof(ETransport.grpc):
item.requestHost = Utils.UrlDecode(query["authority"] ?? "");
item.path = Utils.UrlDecode(query["serviceName"] ?? "");
item.headerType = Utils.UrlDecode(query["mode"] ?? Global.GrpcGunMode);
break;
default:
break;
}
return 0;
}
protected static bool Contains(string str, params string[] s)
{
foreach (var item in s)
{
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
}
return false;
}
protected static string WriteAllText(string strData, string ext = "json")
{
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.{ext}");
File.WriteAllText(fileName, strData);
return fileName;
}
}
}

View File

@@ -0,0 +1,23 @@
namespace ServiceLib.Handler.Fmt
{
public class ClashFmt : BaseFmt
{
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
if (Contains(strData, "port", "socks-port", "proxies"))
{
var fileName = WriteAllText(strData, "yaml");
var profileItem = new ProfileItem
{
coreType = ECoreType.mihomo,
address = fileName,
remarks = subRemarks ?? "clash_custom"
};
return profileItem;
}
return null;
}
}
}

View File

@@ -0,0 +1,90 @@
namespace ServiceLib.Handler.Fmt
{
public class FmtHandler
{
public static string? GetShareUri(ProfileItem item)
{
try
{
var url = item.configType switch
{
EConfigType.VMess => VmessFmt.ToUri(item),
EConfigType.Shadowsocks => ShadowsocksFmt.ToUri(item),
EConfigType.Socks => SocksFmt.ToUri(item),
EConfigType.Trojan => TrojanFmt.ToUri(item),
EConfigType.VLESS => VLESSFmt.ToUri(item),
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
EConfigType.Tuic => TuicFmt.ToUri(item),
EConfigType.Wireguard => WireguardFmt.ToUri(item),
_ => null,
};
return url;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return "";
}
}
public static ProfileItem? ResolveConfig(string config, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
try
{
string str = config.TrimEx();
if (Utils.IsNullOrEmpty(str))
{
msg = ResUI.FailedReadConfiguration;
return null;
}
if (str.StartsWith(Global.ProtocolShares[EConfigType.VMess]))
{
return VmessFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Shadowsocks]))
{
return ShadowsocksFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Socks]))
{
return SocksFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Trojan]))
{
return TrojanFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.VLESS]))
{
return VLESSFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Hysteria2]) || str.StartsWith(Global.Hysteria2ProtocolShare))
{
return Hysteria2Fmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Tuic]))
{
return TuicFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Wireguard]))
{
return WireguardFmt.Resolve(str, out msg);
}
else
{
msg = ResUI.NonvmessOrssProtocol;
return null;
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
msg = ResUI.Incorrectconfiguration;
return null;
}
}
}
}

View File

@@ -0,0 +1,100 @@
namespace ServiceLib.Handler.Fmt
{
public class Hysteria2Fmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
configType = EConfigType.Hysteria2
};
Uri url = new(str);
item.address = url.IdnHost;
item.port = url.Port;
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.path = Utils.UrlDecode(query["obfs-password"] ?? "");
item.allowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.sni))
{
dicQuery.Add("sni", item.sni);
}
if (!Utils.IsNullOrEmpty(item.alpn))
{
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
}
if (!Utils.IsNullOrEmpty(item.path))
{
dicQuery.Add("obfs", "salamander");
dicQuery.Add("obfs-password", Utils.UrlEncode(item.path));
}
dicQuery.Add("insecure", item.allowInsecure.ToLower() == "true" ? "1" : "0");
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
url = string.Format("{0}@{1}:{2}",
item.id,
GetIpv6(item.address),
item.port);
url = $"{Global.ProtocolShares[EConfigType.Hysteria2]}{url}/{query}{remark}";
return url;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
if (Contains(strData, "server", "up", "down", "listen", "<html>", "<body>"))
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
coreType = ECoreType.hysteria,
address = fileName,
remarks = subRemarks ?? "hysteria_custom"
};
return profileItem;
}
return null;
}
public static ProfileItem? ResolveFull2(string strData, string? subRemarks)
{
if (Contains(strData, "server", "auth", "up", "down", "listen"))
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
coreType = ECoreType.hysteria2,
address = fileName,
remarks = subRemarks ?? "hysteria2_custom"
};
return profileItem;
}
return null;
}
}
}

View File

@@ -0,0 +1,23 @@
namespace ServiceLib.Handler.Fmt
{
public class NaiveproxyFmt : BaseFmt
{
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
if (Contains(strData, "listen", "proxy", "<html>", "<body>"))
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
coreType = ECoreType.naiveproxy,
address = fileName,
remarks = subRemarks ?? "naiveproxy_custom"
};
return profileItem;
}
return null;
}
}
}

View File

@@ -0,0 +1,180 @@
using System.Text.RegularExpressions;
namespace ServiceLib.Handler.Fmt
{
public class ShadowsocksFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
item = ResolveSSLegacy(str) ?? ResolveSip002(str);
if (item == null)
{
return null;
}
if (item.address.Length == 0 || item.port == 0 || item.security.Length == 0 || item.id.Length == 0)
{
return null;
}
item.configType = EConfigType.Shadowsocks;
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
//url = string.Format("{0}:{1}@{2}:{3}",
// item.security,
// item.id,
// item.address,
// item.port);
//url = Utile.Base64Encode(url);
//new Sip002
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
url = $"{Global.ProtocolShares[EConfigType.Shadowsocks]}{url}{remark}";
return url;
}
private static readonly Regex UrlFinder = new(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex DetailsParser = new(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static ProfileItem? ResolveSSLegacy(string result)
{
var match = UrlFinder.Match(result);
if (!match.Success)
return null;
ProfileItem item = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (!Utils.IsNullOrEmpty(tag))
{
item.remarks = Utils.UrlDecode(tag);
}
Match details;
try
{
details = DetailsParser.Match(Utils.Base64Decode(base64));
}
catch (FormatException)
{
return null;
}
if (!details.Success)
return null;
item.security = details.Groups["method"].Value;
item.id = details.Groups["password"].Value;
item.address = details.Groups["hostname"].Value;
item.port = Utils.ToInt(details.Groups["port"].Value);
return item;
}
private static ProfileItem? ResolveSip002(string result)
{
Uri parsedUrl;
try
{
parsedUrl = new Uri(result);
}
catch (UriFormatException)
{
return null;
}
ProfileItem item = new()
{
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost,
port = parsedUrl.Port,
};
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
//2022-blake3
if (rawUserInfo.Contains(':'))
{
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.security = userInfoParts[0];
item.id = Utils.UrlDecode(userInfoParts[1]);
}
else
{
// parse base64 UserInfo
string userInfo = Utils.Base64Decode(rawUserInfo);
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.security = userInfoParts[0];
item.id = userInfoParts[1];
}
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
if (queryParameters["plugin"] != null)
{
//obfs-host exists
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
{
obfsHost = obfsHost?.Replace("obfs-host=", "");
item.network = Global.DefaultNetwork;
item.headerType = Global.TcpHeaderHttp;
item.requestHost = obfsHost ?? "";
}
else
{
return null;
}
}
return item;
}
public static List<ProfileItem>? ResolveSip008(string result)
{
//SsSIP008
var lstSsServer = JsonUtils.Deserialize<List<SsServer>>(result);
if (lstSsServer?.Count <= 0)
{
var ssSIP008 = JsonUtils.Deserialize<SsSIP008>(result);
if (ssSIP008?.servers?.Count > 0)
{
lstSsServer = ssSIP008.servers;
}
}
if (lstSsServer?.Count > 0)
{
List<ProfileItem> lst = [];
foreach (var it in lstSsServer)
{
var ssItem = new ProfileItem()
{
remarks = it.remarks,
security = it.method,
id = it.password,
address = it.server,
port = Utils.ToInt(it.server_port)
};
lst.Add(ssItem);
}
return lst;
}
return null;
}
}
}

View File

@@ -0,0 +1,55 @@
namespace ServiceLib.Handler.Fmt
{
public class SingboxFmt : BaseFmt
{
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
{
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
if (configObjects != null && configObjects.Length > 0)
{
List<ProfileItem> lstResult = [];
foreach (var configObject in configObjects)
{
var objectString = JsonUtils.Serialize(configObject);
var singboxCon = JsonUtils.Deserialize<SingboxConfig>(objectString);
if (singboxCon?.inbounds?.Count > 0
&& singboxCon.outbounds?.Count > 0
&& singboxCon.route != null)
{
var fileName = WriteAllText(objectString);
var profileIt = new ProfileItem
{
coreType = ECoreType.sing_box,
address = fileName,
remarks = subRemarks ?? "singbox_custom",
};
lstResult.Add(profileIt);
}
}
return lstResult;
}
return null;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(strData);
if (singboxConfig?.inbounds?.Count > 0
&& singboxConfig.outbounds?.Count > 0
&& singboxConfig.route != null)
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
coreType = ECoreType.sing_box,
address = fileName,
remarks = subRemarks ?? "singbox_custom"
};
return profileItem;
}
return null;
}
}
}

View File

@@ -0,0 +1,127 @@
namespace ServiceLib.Handler.Fmt
{
public class SocksFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
item = ResolveSocksNew(str) ?? ResolveSocks(str);
if (item == null)
{
return null;
}
if (item.address.Length == 0 || item.port == 0)
{
return null;
}
item.configType = EConfigType.Socks;
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
//url = string.Format("{0}:{1}@{2}:{3}",
// item.security,
// item.id,
// item.address,
// item.port);
//url = Utile.Base64Encode(url);
//new
var pw = Utils.Base64Encode($"{item.security}:{item.id}");
url = $"{pw}@{GetIpv6(item.address)}:{item.port}";
url = $"{Global.ProtocolShares[EConfigType.Socks]}{url}{remark}";
return url;
}
private static ProfileItem? ResolveSocks(string result)
{
ProfileItem item = new()
{
configType = EConfigType.Socks
};
result = result[Global.ProtocolShares[EConfigType.Socks].Length..];
//remark
int indexRemark = result.IndexOf("#");
if (indexRemark > 0)
{
try
{
item.remarks = Utils.UrlDecode(result.Substring(indexRemark + 1, result.Length - indexRemark - 1));
}
catch { }
result = result[..indexRemark];
}
//part decode
int indexS = result.IndexOf("@");
if (indexS > 0)
{
}
else
{
result = Utils.Base64Decode(result);
}
string[] arr1 = result.Split('@');
if (arr1.Length != 2)
{
return null;
}
string[] arr21 = arr1[0].Split(':');
//string[] arr22 = arr1[1].Split(':');
int indexPort = arr1[1].LastIndexOf(":");
if (arr21.Length != 2 || indexPort < 0)
{
return null;
}
item.address = arr1[1][..indexPort];
item.port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
item.security = arr21[0];
item.id = arr21[1];
return item;
}
private static ProfileItem? ResolveSocksNew(string result)
{
Uri parsedUrl;
try
{
parsedUrl = new Uri(result);
}
catch (UriFormatException)
{
return null;
}
ProfileItem item = new()
{
remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
address = parsedUrl.IdnHost,
port = parsedUrl.Port,
};
// parse base64 UserInfo
string rawUserInfo = parsedUrl.GetComponents(UriComponents.UserInfo, UriFormat.Unescaped);
string userInfo = Utils.Base64Decode(rawUserInfo);
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2)
{
item.security = userInfoParts[0];
item.id = userInfoParts[1];
}
return item;
}
}
}

View File

@@ -0,0 +1,49 @@
namespace ServiceLib.Handler.Fmt
{
public class TrojanFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
configType = EConfigType.Trojan
};
Uri url = new(str);
item.address = url.IdnHost;
item.port = url.Port;
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
GetStdTransport(item, null, ref dicQuery);
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
url = string.Format("{0}@{1}:{2}",
item.id,
GetIpv6(item.address),
item.port);
url = $"{Global.ProtocolShares[EConfigType.Trojan]}{url}{query}{remark}";
return url;
}
}
}

View File

@@ -0,0 +1,64 @@
namespace ServiceLib.Handler.Fmt
{
public class TuicFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
configType = EConfigType.Tuic
};
Uri url = new(str);
item.address = url.IdnHost;
item.port = url.Port;
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
var userInfoParts = url.UserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2)
{
item.id = userInfoParts[0];
item.security = userInfoParts[1];
}
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
item.headerType = query["congestion_control"] ?? "";
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.sni))
{
dicQuery.Add("sni", item.sni);
}
if (!Utils.IsNullOrEmpty(item.alpn))
{
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
}
dicQuery.Add("congestion_control", item.headerType);
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
url = string.Format("{0}@{1}:{2}",
$"{item.id}:{item.security}",
GetIpv6(item.address),
item.port);
url = $"{Global.ProtocolShares[EConfigType.Tuic]}{url}{query}{remark}";
return url;
}
}
}

View File

@@ -0,0 +1,56 @@
namespace ServiceLib.Handler.Fmt
{
public class V2rayFmt : BaseFmt
{
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
{
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
if (configObjects != null && configObjects.Length > 0)
{
List<ProfileItem> lstResult = [];
foreach (var configObject in configObjects)
{
var objectString = JsonUtils.Serialize(configObject);
var v2rayCon = JsonUtils.Deserialize<V2rayConfig>(objectString);
if (v2rayCon?.inbounds?.Count > 0
&& v2rayCon.outbounds?.Count > 0
&& v2rayCon.routing != null)
{
var fileName = WriteAllText(objectString);
var profileIt = new ProfileItem
{
coreType = ECoreType.Xray,
address = fileName,
remarks = v2rayCon.remarks ?? subRemarks ?? "v2ray_custom",
};
lstResult.Add(profileIt);
}
}
return lstResult;
}
return null;
}
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
{
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(strData);
if (v2rayConfig?.inbounds?.Count > 0
&& v2rayConfig.outbounds?.Count > 0
&& v2rayConfig.routing != null)
{
var fileName = WriteAllText(strData);
var profileItem = new ProfileItem
{
coreType = ECoreType.Xray,
address = fileName,
remarks = v2rayConfig.remarks ?? subRemarks ?? "v2ray_custom"
};
return profileItem;
}
return null;
}
}
}

View File

@@ -0,0 +1,60 @@
namespace ServiceLib.Handler.Fmt
{
public class VLESSFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
configType = EConfigType.VLESS,
security = Global.None
};
Uri url = new(str);
item.address = url.IdnHost;
item.port = url.Port;
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
item.security = query["encryption"] ?? Global.None;
item.streamSecurity = query["security"] ?? "";
ResolveStdTransport(query, ref item);
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.security))
{
dicQuery.Add("encryption", item.security);
}
else
{
dicQuery.Add("encryption", Global.None);
}
GetStdTransport(item, Global.None, ref dicQuery);
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
url = string.Format("{0}@{1}:{2}",
item.id,
GetIpv6(item.address),
item.port);
url = $"{Global.ProtocolShares[EConfigType.VLESS]}{url}{query}{remark}";
return url;
}
}
}

View File

@@ -0,0 +1,122 @@
namespace ServiceLib.Handler.Fmt
{
public class VmessFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
{
item = ResolveStdVmess(str);
}
else
{
item = ResolveVmess(str, out msg);
}
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
VmessQRCode vmessQRCode = new()
{
v = item.configVersion,
ps = item.remarks.TrimEx(),
add = item.address,
port = item.port,
id = item.id,
aid = item.alterId,
scy = item.security,
net = item.network,
type = item.headerType,
host = item.requestHost,
path = item.path,
tls = item.streamSecurity,
sni = item.sni,
alpn = item.alpn,
fp = item.fingerprint
};
url = JsonUtils.Serialize(vmessQRCode);
url = Utils.Base64Encode(url);
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
return url;
}
private static ProfileItem? ResolveVmess(string result, out string msg)
{
msg = string.Empty;
var item = new ProfileItem
{
configType = EConfigType.VMess
};
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
result = Utils.Base64Decode(result);
//转成Json
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
if (vmessQRCode == null)
{
msg = ResUI.FailedConversionConfiguration;
return null;
}
item.network = Global.DefaultNetwork;
item.headerType = Global.None;
item.configVersion = Utils.ToInt(vmessQRCode.v);
item.remarks = Utils.ToString(vmessQRCode.ps);
item.address = Utils.ToString(vmessQRCode.add);
item.port = Utils.ToInt(vmessQRCode.port);
item.id = Utils.ToString(vmessQRCode.id);
item.alterId = Utils.ToInt(vmessQRCode.aid);
item.security = Utils.ToString(vmessQRCode.scy);
item.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
{
item.network = vmessQRCode.net;
}
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
{
item.headerType = vmessQRCode.type;
}
item.requestHost = Utils.ToString(vmessQRCode.host);
item.path = Utils.ToString(vmessQRCode.path);
item.streamSecurity = Utils.ToString(vmessQRCode.tls);
item.sni = Utils.ToString(vmessQRCode.sni);
item.alpn = Utils.ToString(vmessQRCode.alpn);
item.fingerprint = Utils.ToString(vmessQRCode.fp);
return item;
}
public static ProfileItem? ResolveStdVmess(string str)
{
ProfileItem item = new()
{
configType = EConfigType.VMess,
security = "auto"
};
Uri url = new(str);
item.address = url.IdnHost;
item.port = url.Port;
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
return item;
}
}
}

View File

@@ -0,0 +1,69 @@
namespace ServiceLib.Handler.Fmt
{
public class WireguardFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem item = new()
{
configType = EConfigType.Wireguard
};
Uri url = new(str);
item.address = url.IdnHost;
item.port = url.Port;
item.remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
item.id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
item.publicKey = Utils.UrlDecode(query["publickey"] ?? "");
item.path = Utils.UrlDecode(query["reserved"] ?? "");
item.requestHost = Utils.UrlDecode(query["address"] ?? "");
item.shortId = Utils.UrlDecode(query["mtu"] ?? "");
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.publicKey))
{
dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey));
}
if (!Utils.IsNullOrEmpty(item.path))
{
dicQuery.Add("reserved", Utils.UrlEncode(item.path));
}
if (!Utils.IsNullOrEmpty(item.requestHost))
{
dicQuery.Add("address", Utils.UrlEncode(item.requestHost));
}
if (!Utils.IsNullOrEmpty(item.shortId))
{
dicQuery.Add("mtu", Utils.UrlEncode(item.shortId));
}
string query = "?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray());
url = string.Format("{0}@{1}:{2}",
Utils.UrlEncode(item.id),
GetIpv6(item.address),
item.port);
url = $"{Global.ProtocolShares[EConfigType.Wireguard]}{url}/{query}{remark}";
return url;
}
}
}

View File

@@ -0,0 +1,242 @@
namespace ServiceLib.Handler
{
public sealed class LazyConfig
{
private static readonly Lazy<LazyConfig> _instance = new(() => new());
private Config _config;
private int? _statePort;
private int? _statePort2;
public static LazyConfig Instance => _instance.Value;
public Config Config => _config;
public int StatePort
{
get
{
_statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api));
return _statePort.Value;
}
}
public int StatePort2
{
get
{
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
return _statePort2.Value;
}
}
private Job? _processJob;
public LazyConfig()
{
SQLiteHelper.Instance.CreateTable<SubItem>();
SQLiteHelper.Instance.CreateTable<ProfileItem>();
SQLiteHelper.Instance.CreateTable<ServerStatItem>();
SQLiteHelper.Instance.CreateTable<RoutingItem>();
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
SQLiteHelper.Instance.CreateTable<DNSItem>();
}
#region Config
public void SetConfig(Config config) => _config = config;
public int GetLocalPort(EInboundProtocol protocol)
{
var localPort = _config.inbound.FirstOrDefault(t => t.protocol == nameof(EInboundProtocol.socks))?.localPort ?? 10808;
return localPort + (int)protocol;
}
public void AddProcess(IntPtr processHandle)
{
if (Utils.IsWindows())
{
_processJob ??= new();
_processJob?.AddProcess(processHandle);
}
}
#endregion Config
#region SqliteHelper
public List<SubItem> SubItems()
{
return SQLiteHelper.Instance.Table<SubItem>().ToList();
}
public SubItem GetSubItem(string subid)
{
return SQLiteHelper.Instance.Table<SubItem>().FirstOrDefault(t => t.id == subid);
}
public List<ProfileItem> ProfileItems(string subid)
{
if (Utils.IsNullOrEmpty(subid))
{
return SQLiteHelper.Instance.Table<ProfileItem>().ToList();
}
else
{
return SQLiteHelper.Instance.Table<ProfileItem>().Where(t => t.subid == subid).ToList();
}
}
public List<string> ProfileItemIndexes(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)
{
var sql = @$"select a.*
,b.remarks subRemarks
from ProfileItem a
left join SubItem b on a.subid = b.id
where 1=1 ";
if (!Utils.IsNullOrEmpty(subid))
{
sql += $" and a.subid = '{subid}'";
}
if (!Utils.IsNullOrEmpty(filter))
{
if (filter.Contains('\''))
{
filter = filter.Replace("'", "");
}
sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter);
}
return SQLiteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
}
public List<ProfileItemModel> ProfileItemsEx(string subid, string filter)
{
var lstModel = ProfileItems(_config.subIndexId, filter);
ConfigHandler.SetDefaultServer(_config, lstModel);
var lstServerStat = (_config.guiItem.enableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
lstModel = (from t in lstModel
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
indexId = t.indexId,
configType = t.configType,
remarks = t.remarks,
address = t.address,
port = t.port,
security = t.security,
network = t.network,
streamSecurity = t.streamSecurity,
subid = t.subid,
subRemarks = t.subRemarks,
isActive = t.indexId == _config.indexId,
sort = t33 == null ? 0 : t33.sort,
delay = t33 == null ? 0 : t33.delay,
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).OrderBy(t => t.sort).ToList();
return lstModel;
}
public ProfileItem? GetProfileItem(string indexId)
{
if (Utils.IsNullOrEmpty(indexId))
{
return null;
}
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.indexId == indexId);
}
public ProfileItem? GetProfileItemViaRemarks(string remarks)
{
if (Utils.IsNullOrEmpty(remarks))
{
return null;
}
return SQLiteHelper.Instance.Table<ProfileItem>().FirstOrDefault(it => it.remarks == remarks);
}
public List<RoutingItem> RoutingItems()
{
return SQLiteHelper.Instance.Table<RoutingItem>().Where(it => it.locked == false).OrderBy(t => t.sort).ToList();
}
public RoutingItem GetRoutingItem(string id)
{
return SQLiteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == false && it.id == id);
}
public List<DNSItem> DNSItems()
{
return SQLiteHelper.Instance.Table<DNSItem>().ToList();
}
public DNSItem GetDNSItem(ECoreType eCoreType)
{
return SQLiteHelper.Instance.Table<DNSItem>().FirstOrDefault(it => it.coreType == eCoreType);
}
#endregion SqliteHelper
#region Core Type
public List<string> GetShadowsocksSecurities(ProfileItem profileItem)
{
var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks);
switch (coreType)
{
case ECoreType.v2fly:
return Global.SsSecurities;
case ECoreType.Xray:
return Global.SsSecuritiesInXray;
case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox;
}
return Global.SsSecuritiesInSagerNet;
}
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
{
if (profileItem?.coreType != null)
{
return (ECoreType)profileItem.coreType;
}
if (_config.coreTypeItem == null)
{
return ECoreType.Xray;
}
var item = _config.coreTypeItem.FirstOrDefault(it => it.configType == eConfigType);
if (item == null)
{
return ECoreType.Xray;
}
return item.coreType;
}
#endregion Core Type
}
}

View File

@@ -0,0 +1,41 @@
using ReactiveUI;
namespace ServiceLib.Handler
{
public class NoticeHandler
{
public void Enqueue(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
MessageBus.Current.SendMessage(content, Global.CommandSendSnackMsg);
}
public void SendMessage(string? content)
{
if (content.IsNullOrEmpty())
{
return;
}
MessageBus.Current.SendMessage(content, Global.CommandSendMsgView);
}
public void SendMessage(string? content, bool time)
{
if (content.IsNullOrEmpty())
{
return;
}
content = $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} {content}";
SendMessage(content);
}
public void SendMessageAndEnqueue(string? msg)
{
Enqueue(msg);
SendMessage(msg);
}
}
}

View File

@@ -1,14 +1,13 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Reactive.Linq;
using v2rayN.Base;
using v2rayN.Mode;
namespace v2rayN.Handler //using System.Reactive.Linq;
namespace ServiceLib.Handler
{ {
internal class ProfileExHandler public class ProfileExHandler
{ {
private static readonly Lazy<ProfileExHandler> _instance = new(() => new()); private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx; private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
private Queue<string> _queIndexIds = new(); private Queue<string> _queIndexIds = new();
public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx; public ConcurrentBag<ProfileExItem> ProfileExs => _lstProfileEx;
public static ProfileExHandler Instance => _instance.Value; public static ProfileExHandler Instance => _instance.Value;
@@ -16,33 +15,24 @@ namespace v2rayN.Handler
public ProfileExHandler() public ProfileExHandler()
{ {
Init(); 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(async () => Task.Run(async () =>
{ {
while (true) while (true)
{ {
var cnt = _queIndexIds.Count; SaveQueueIndexIds();
for (int i = 0; i < cnt; i++) await Task.Delay(1000 * 600);
{
var id = _queIndexIds.Dequeue();
var item = _lstProfileEx.FirstOrDefault(t => t.indexId == id);
if (item is not null)
{
SqliteHelper.Instance.Replace(item);
}
}
await Task.Delay(1000 * 60);
} }
}); });
} }
private void Init()
{
SQLiteHelper.Instance.Execute($"delete from ProfileExItem where indexId not in ( select indexId from ProfileItem )");
_lstProfileEx = new(SQLiteHelper.Instance.Table<ProfileExItem>());
}
private void IndexIdEnqueue(string indexId) private void IndexIdEnqueue(string indexId)
{ {
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId)) if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
@@ -51,7 +41,50 @@ namespace v2rayN.Handler
} }
} }
private void AddProfileEx(string indexId, ref ProfileExItem profileEx) private void SaveQueueIndexIds()
{
var cnt = _queIndexIds.Count;
if (cnt > 0)
{
var lstExists = SQLiteHelper.Instance.Table<ProfileExItem>();
List<ProfileExItem> lstInserts = [];
List<ProfileExItem> lstUpdates = [];
for (int i = 0; i < cnt; i++)
{
var id = _queIndexIds.Dequeue();
var item = lstExists.FirstOrDefault(t => t.indexId == id);
var itemNew = _lstProfileEx?.FirstOrDefault(t => t.indexId == id);
if (itemNew is null)
{
continue;
}
if (item is not null)
{
lstUpdates.Add(itemNew);
}
else
{
lstInserts.Add(itemNew);
}
}
try
{
if (lstInserts.Count() > 0)
SQLiteHelper.Instance.InsertAll(lstInserts);
if (lstUpdates.Count() > 0)
SQLiteHelper.Instance.UpdateAll(lstUpdates);
}
catch (Exception ex)
{
Logging.SaveLog("ProfileExHandler", ex);
}
}
}
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx)
{ {
profileEx = new() profileEx = new()
{ {
@@ -66,7 +99,7 @@ namespace v2rayN.Handler
public void ClearAll() public void ClearAll()
{ {
SqliteHelper.Instance.Execute($"delete from ProfileExItem "); SQLiteHelper.Instance.Execute($"delete from ProfileExItem ");
_lstProfileEx = new(); _lstProfileEx = new();
} }
@@ -74,15 +107,11 @@ namespace v2rayN.Handler
{ {
try try
{ {
//foreach (var item in _lstProfileEx) SaveQueueIndexIds();
//{
// SqliteHelper.Instance.Replace(item);
//}
SqliteHelper.Instance.UpdateAll(_lstProfileEx);
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }

View File

@@ -1,26 +1,19 @@
using System.Diagnostics; using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets; using System.Net.Sockets;
using v2rayN.Mode;
using v2rayN.Resx;
namespace v2rayN.Handler namespace ServiceLib.Handler
{ {
internal class SpeedtestHandler public 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;
private Action<string, string, string> _updateFunc; private Action<SpeedTestResult> _updateFunc;
private bool _exitLoop = false;
public SpeedtestHandler(Config config) public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> update)
{
_config = config;
}
public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<string, string, string> update)
{ {
_config = config; _config = config;
_coreHandler = coreHandler; _coreHandler = coreHandler;
@@ -30,7 +23,7 @@ namespace v2rayN.Handler
_selecteds = new List<ServerTestItem>(); _selecteds = new List<ServerTestItem>();
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
if (it.configType == EConfigType.Custom || it.configType == EConfigType.Hysteria2) if (it.configType == EConfigType.Custom)
{ {
continue; continue;
} }
@@ -51,7 +44,6 @@ namespace v2rayN.Handler
{ {
switch (actionType) switch (actionType)
{ {
case ESpeedActionType.Ping:
case ESpeedActionType.Tcping: case ESpeedActionType.Tcping:
case ESpeedActionType.Realping: case ESpeedActionType.Realping:
UpdateFunc(it.indexId, ResUI.Speedtesting, ""); UpdateFunc(it.indexId, ResUI.Speedtesting, "");
@@ -73,10 +65,6 @@ namespace v2rayN.Handler
switch (actionType) switch (actionType)
{ {
case ESpeedActionType.Ping:
Task.Run(RunPing);
break;
case ESpeedActionType.Tcping: case ESpeedActionType.Tcping:
Task.Run(RunTcping); Task.Run(RunTcping);
break; break;
@@ -95,52 +83,51 @@ namespace v2rayN.Handler
} }
} }
private async Task RunPingSubAsync(Action<ServerTestItem> updateFun) public void ExitLoop()
{
_exitLoop = true;
UpdateFunc("", ResUI.SpeedtestingStop);
}
private Task RunTcping()
{ {
try try
{ {
foreach (var it in _selecteds.Where(it => it.configType != EConfigType.Custom)) List<Task> tasks = [];
foreach (var it in _selecteds)
{ {
try if (it.configType == EConfigType.Custom)
{ {
Task.Run(() => updateFun(it)); continue;
} }
catch (Exception ex) tasks.Add(Task.Run(() =>
{ {
Utils.SaveLog(ex.Message, ex); try
} {
} int time = GetTcpingTime(it.address, it.port);
var output = FormatOut(time, Global.DelayUnit);
await Task.Delay(10); ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}));
}
Task.WaitAll([.. tasks]);
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} finally
private async void RunPing()
{
await RunPingSubAsync((ServerTestItem it) =>
{
long time = Ping(it.address);
var output = FormatOut(time, Global.DelayUnit);
ProfileExHandler.Instance.SetTestDelay(it.indexId, output);
UpdateFunc(it.indexId, output);
});
}
private async void RunTcping()
{
await RunPingSubAsync((ServerTestItem it) =>
{ {
int time = GetTcpingTime(it.address, it.port); ProfileExHandler.Instance.SaveTo();
var output = FormatOut(time, Global.DelayUnit); }
ProfileExHandler.Instance.SetTestDelay(it.indexId, output); return Task.CompletedTask;
UpdateFunc(it.indexId, output);
});
} }
private Task RunRealPing() private Task RunRealPing()
@@ -150,14 +137,14 @@ namespace v2rayN.Handler
{ {
string msg = string.Empty; string msg = string.Empty;
pid = _coreHandler.LoadCoreConfigString(_selecteds); pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
if (pid < 0) if (pid < 0)
{ {
UpdateFunc("", ResUI.FailedToRunCore); UpdateFunc("", ResUI.FailedToRunCore);
return Task.CompletedTask; return Task.CompletedTask;
} }
DownloadHandle downloadHandle = new DownloadHandle(); DownloadHandler downloadHandle = new DownloadHandler();
List<Task> tasks = new(); List<Task> tasks = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
@@ -184,7 +171,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
})); }));
} }
@@ -192,11 +179,14 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
finally finally
{ {
if (pid > 0) _coreHandler.CoreStopPid(pid); if (pid > 0)
{
_coreHandler.CoreStopPid(pid);
}
ProfileExHandler.Instance.SaveTo(); ProfileExHandler.Instance.SaveTo();
} }
@@ -211,7 +201,7 @@ namespace v2rayN.Handler
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList(); // _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
//} //}
pid = _coreHandler.LoadCoreConfigString(_selecteds); pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
if (pid < 0) if (pid < 0)
{ {
UpdateFunc("", ResUI.FailedToRunCore); UpdateFunc("", ResUI.FailedToRunCore);
@@ -221,10 +211,15 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl; string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout; var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new(); DownloadHandler downloadHandle = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (_exitLoop)
{
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
continue;
}
if (!it.allowTest) if (!it.allowTest)
{ {
continue; continue;
@@ -268,7 +263,7 @@ namespace v2rayN.Handler
private async Task RunSpeedTestMulti() private async Task RunSpeedTestMulti()
{ {
int pid = -1; int pid = -1;
pid = _coreHandler.LoadCoreConfigString(_selecteds); pid = _coreHandler.LoadCoreConfigSpeedtest(_selecteds);
if (pid < 0) if (pid < 0)
{ {
UpdateFunc("", ResUI.FailedToRunCore); UpdateFunc("", ResUI.FailedToRunCore);
@@ -278,10 +273,16 @@ namespace v2rayN.Handler
string url = _config.speedTestItem.speedTestUrl; string url = _config.speedTestItem.speedTestUrl;
var timeout = _config.speedTestItem.speedTestTimeout; var timeout = _config.speedTestItem.speedTestTimeout;
DownloadHandle downloadHandle = new(); DownloadHandler downloadHandle = new();
foreach (var it in _selecteds) foreach (var it in _selecteds)
{ {
if (_exitLoop)
{
UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip);
continue;
}
if (!it.allowTest) if (!it.allowTest)
{ {
continue; continue;
@@ -333,10 +334,10 @@ namespace v2rayN.Handler
await RunSpeedTestMulti(); await RunSpeedTestMulti();
} }
public async Task<string> GetRealPingTime(DownloadHandle downloadHandle, IWebProxy webProxy) private async Task<string> GetRealPingTime(DownloadHandler downloadHandle, IWebProxy webProxy)
{ {
int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10); int responseTime = await downloadHandle.GetRealPingTime(_config.speedTestItem.speedPingTestUrl, webProxy, 10);
//string output = Utils.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status; //string output = Utile.IsNullOrEmpty(status) ? FormatOut(responseTime, "ms") : status;
return FormatOut(responseTime, Global.DelayUnit); return FormatOut(responseTime, Global.DelayUnit);
} }
@@ -346,70 +347,32 @@ namespace v2rayN.Handler
try try
{ {
if (!IPAddress.TryParse(url, out IPAddress ipAddress)) if (!IPAddress.TryParse(url, out IPAddress? ipAddress))
{ {
IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url); IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(url);
ipAddress = ipHostInfo.AddressList[0]; ipAddress = ipHostInfo.AddressList[0];
} }
Stopwatch timer = new(); var timer = Stopwatch.StartNew();
timer.Start();
IPEndPoint endPoint = new(ipAddress, port); IPEndPoint endPoint = new(ipAddress, port);
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = clientSocket.BeginConnect(endPoint, null, null); var result = clientSocket.BeginConnect(endPoint, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))) if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
throw new TimeoutException("connect timeout (5s): " + url); throw new TimeoutException("connect timeout (5s): " + url);
clientSocket.EndConnect(result); clientSocket.EndConnect(result);
timer.Stop(); timer.Stop();
responseTime = timer.Elapsed.Milliseconds; responseTime = (int)timer.Elapsed.TotalMilliseconds;
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return responseTime; return responseTime;
} }
/// <summary>
/// Ping
/// </summary>
/// <param name="host"></param>
/// <returns></returns>
public long Ping(string host)
{
long roundtripTime = -1;
try
{
int timeout = 30;
int echoNum = 2;
using Ping pingSender = new();
for (int i = 0; i < echoNum; i++)
{
PingReply reply = pingSender.Send(host, timeout);
if (reply.Status == IPStatus.Success)
{
if (reply.RoundtripTime < 0)
{
continue;
}
if (roundtripTime < 0 || reply.RoundtripTime < roundtripTime)
{
roundtripTime = reply.RoundtripTime;
}
}
}
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
return -1;
}
return roundtripTime;
}
private string FormatOut(object time, string unit) private string FormatOut(object time, string unit)
{ {
//if (time.ToString().Equals("-1")) //if (time.ToString().Equals("-1"))
@@ -421,7 +384,7 @@ namespace v2rayN.Handler
private void UpdateFunc(string indexId, string delay, string speed = "") private void UpdateFunc(string indexId, string delay, string speed = "")
{ {
_updateFunc(indexId, delay, speed); _updateFunc(new() { IndexId = indexId, Delay = delay, Speed = speed });
} }
} }
} }

View File

@@ -1,12 +1,10 @@
using System.Net; namespace ServiceLib.Handler.Statistics
using System.Net.Sockets;
using v2rayN.Base;
using v2rayN.Mode;
namespace v2rayN.Handler
{ {
internal class StatisticsHandler public class StatisticsHandler
{ {
private static readonly Lazy<StatisticsHandler> instance = new(() => new());
public static StatisticsHandler Instance => instance.Value;
private Config _config; private Config _config;
private ServerStatItem? _serverStatItem; private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat; private List<ServerStatItem> _lstServerStat;
@@ -15,21 +13,17 @@ namespace v2rayN.Handler
private StatisticsSingbox? _statisticsSingbox; private StatisticsSingbox? _statisticsSingbox;
public List<ServerStatItem> ServerStat => _lstServerStat; public List<ServerStatItem> ServerStat => _lstServerStat;
public bool Enable { get; set; }
public StatisticsHandler(Config config, Action<ServerSpeedItem> update) public void Init(Config config, Action<ServerSpeedItem> update)
{ {
_config = config; _config = config;
Enable = config.guiItem.enableStatistics; _updateFunc = update;
if (!Enable) if (!config.guiItem.enableStatistics)
{ {
return; return;
} }
_updateFunc = update; InitData();
Init();
Global.statePort = GetFreePort();
_statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat); _statisticsV2Ray = new StatisticsV2ray(config, UpdateServerStat);
_statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat); _statisticsSingbox = new StatisticsSingbox(config, UpdateServerStat);
@@ -44,13 +38,13 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }
public void ClearAllServerStatistics() public void ClearAllServerStatistics()
{ {
SqliteHelper.Instance.Execute($"delete from ServerStatItem "); SQLiteHelper.Instance.Execute($"delete from ServerStatItem ");
_serverStatItem = null; _serverStatItem = null;
_lstServerStat = new(); _lstServerStat = new();
} }
@@ -59,28 +53,35 @@ namespace v2rayN.Handler
{ {
try try
{ {
SqliteHelper.Instance.UpdateAll(_lstServerStat); if (_lstServerStat != null)
{
SQLiteHelper.Instance.UpdateAll(_lstServerStat);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }
private void Init() private void InitData()
{ {
SqliteHelper.Instance.Execute($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )"); 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}");
_lstServerStat = SqliteHelper.Instance.Table<ServerStatItem>().ToList(); _lstServerStat = SQLiteHelper.Instance.Table<ServerStatItem>().ToList();
} }
private void UpdateServerStat(ServerSpeedItem server) private void UpdateServerStat(ServerSpeedItem server)
{ {
GetServerStatItem(_config.indexId); GetServerStatItem(_config.indexId);
if (_serverStatItem is null)
{
return;
}
if (server.proxyUp != 0 || server.proxyDown != 0) if (server.proxyUp != 0 || server.proxyDown != 0)
{ {
_serverStatItem.todayUp += server.proxyUp; _serverStatItem.todayUp += server.proxyUp;
@@ -88,15 +89,13 @@ namespace v2rayN.Handler
_serverStatItem.totalUp += server.proxyUp; _serverStatItem.totalUp += server.proxyUp;
_serverStatItem.totalDown += server.proxyDown; _serverStatItem.totalDown += server.proxyDown;
} }
if (Global.ShowInTaskbar)
{ server.indexId = _config.indexId;
server.indexId = _config.indexId; server.todayUp = _serverStatItem.todayUp;
server.todayUp = _serverStatItem.todayUp; 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);
}
} }
private void GetServerStatItem(string indexId) private void GetServerStatItem(string indexId)
@@ -121,7 +120,7 @@ namespace v2rayN.Handler
todayDown = 0, todayDown = 0,
dateNow = ticks dateNow = ticks
}; };
SqliteHelper.Instance.Replace(_serverStatItem); SQLiteHelper.Instance.Replace(_serverStatItem);
_lstServerStat.Add(_serverStatItem); _lstServerStat.Add(_serverStatItem);
} }
} }
@@ -133,29 +132,5 @@ namespace v2rayN.Handler
_serverStatItem.dateNow = ticks; _serverStatItem.dateNow = ticks;
} }
} }
private int GetFreePort()
{
try
{
int defaultPort = 9090;
if (!Utils.PortInUse(defaultPort))
{
return defaultPort;
}
for (int i = 0; i < 3; i++)
{
TcpListener l = new(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
}
catch
{
}
return 69090;
}
} }
} }

View File

@@ -1,10 +1,9 @@
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using v2rayN.Mode;
namespace v2rayN.Handler namespace ServiceLib.Handler.Statistics
{ {
internal class StatisticsSingbox public class StatisticsSingbox
{ {
private Config _config; private Config _config;
private bool _exitFlag; private bool _exitFlag;
@@ -27,7 +26,7 @@ namespace v2rayN.Handler
try try
{ {
url = $"ws://{Global.Loopback}:{Global.statePort}/traffic"; url = $"ws://{Global.Loopback}:{LazyConfig.Instance.StatePort2}/traffic";
if (webSocket == null) if (webSocket == null)
{ {
@@ -51,7 +50,7 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
} }
@@ -61,8 +60,13 @@ namespace v2rayN.Handler
while (!_exitFlag) while (!_exitFlag)
{ {
await Task.Delay(1000);
try try
{ {
if (!(_config.IsRunningCore(ECoreType.clash)))
{
continue;
}
if (webSocket != null) if (webSocket != null)
{ {
if (webSocket.State == WebSocketState.Aborted if (webSocket.State == WebSocketState.Aborted
@@ -84,7 +88,7 @@ namespace v2rayN.Handler
while (!res.CloseStatus.HasValue) while (!res.CloseStatus.HasValue)
{ {
var result = Encoding.UTF8.GetString(buffer, 0, res.Count); var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
if (!string.IsNullOrEmpty(result)) if (!Utils.IsNullOrEmpty(result))
{ {
ParseOutput(result, out ulong up, out ulong down); ParseOutput(result, out ulong up, out ulong down);
@@ -101,10 +105,6 @@ namespace v2rayN.Handler
catch catch
{ {
} }
finally
{
await Task.Delay(1000);
}
} }
} }
@@ -113,7 +113,7 @@ namespace v2rayN.Handler
up = 0; down = 0; up = 0; down = 0;
try try
{ {
var trafficItem = Utils.FromJson<TrafficItem>(source); var trafficItem = JsonUtils.Deserialize<TrafficItem>(source);
if (trafficItem != null) if (trafficItem != null)
{ {
up = trafficItem.up; up = trafficItem.up;

View File

@@ -1,19 +1,18 @@
using Grpc.Core; using Grpc.Core;
using Grpc.Net.Client; using Grpc.Net.Client;
using ProtosLib.Statistics; using ProtosLib.Statistics;
using v2rayN.Mode;
namespace v2rayN.Handler namespace ServiceLib.Handler.Statistics
{ {
internal class StatisticsV2ray public class StatisticsV2ray
{ {
private Mode.Config _config; private Models.Config _config;
private GrpcChannel _channel; private GrpcChannel? _channel;
private StatsService.StatsServiceClient _client; private StatsService.StatsServiceClient? _client;
private bool _exitFlag; private bool _exitFlag;
private Action<ServerSpeedItem> _updateFunc; private Action<ServerSpeedItem> _updateFunc;
public StatisticsV2ray(Mode.Config config, Action<ServerSpeedItem> update) public StatisticsV2ray(Models.Config config, Action<ServerSpeedItem> update)
{ {
_config = config; _config = config;
_updateFunc = update; _updateFunc = update;
@@ -26,10 +25,17 @@ namespace v2rayN.Handler
private void GrpcInit() private void GrpcInit()
{ {
if (_channel == null) if (_channel is null)
{ {
_channel = GrpcChannel.ForAddress($"{Global.httpProtocol}{Global.Loopback}:{Global.statePort}"); try
_client = new StatsService.StatsServiceClient(_channel); {
_channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{LazyConfig.Instance.StatePort}");
_client = new StatsService.StatsServiceClient(_channel);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
} }
} }
@@ -42,14 +48,20 @@ namespace v2rayN.Handler
{ {
while (!_exitFlag) while (!_exitFlag)
{ {
await Task.Delay(1000);
try try
{ {
if (_channel.State == ConnectivityState.Ready) if (!(_config.IsRunningCore(ECoreType.Xray)))
{
continue;
}
if (_channel?.State == ConnectivityState.Ready)
{ {
QueryStatsResponse? res = null; QueryStatsResponse? res = null;
try try
{ {
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true }); if (_client != null)
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
} }
catch catch
{ {
@@ -61,8 +73,8 @@ namespace v2rayN.Handler
_updateFunc(server); _updateFunc(server);
} }
} }
await Task.Delay(1000); if (_channel != null)
await _channel.ConnectAsync(); await _channel.ConnectAsync();
} }
catch catch
{ {
@@ -73,6 +85,8 @@ namespace v2rayN.Handler
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server) private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
{ {
server = new(); server = new();
long aggregateProxyUp = 0;
long aggregateProxyDown = 0;
try try
{ {
foreach (Stat stat in source) foreach (Stat stat in source)
@@ -87,18 +101,18 @@ namespace v2rayN.Handler
name = nStr[1]; name = nStr[1];
type = nStr[3]; type = nStr[3];
if (name == Global.agentTag) if (name.StartsWith(Global.ProxyTag))
{ {
if (type == "uplink") if (type == "uplink")
{ {
server.proxyUp = value; aggregateProxyUp += value;
} }
else if (type == "downlink") else if (type == "downlink")
{ {
server.proxyDown = value; aggregateProxyDown += value;
} }
} }
else if (name == Global.directTag) else if (name == Global.DirectTag)
{ {
if (type == "uplink") if (type == "uplink")
{ {
@@ -110,6 +124,8 @@ namespace v2rayN.Handler
} }
} }
} }
server.proxyUp = aggregateProxyUp;
server.proxyDown = aggregateProxyDown;
} }
catch catch
{ {

View File

@@ -0,0 +1,76 @@
namespace ServiceLib.Handler
{
public class TaskHandler
{
private static readonly Lazy<TaskHandler> _instance = new(() => new());
public static TaskHandler Instance => _instance.Value;
public TaskHandler()
{
}
public void RegUpdateTask(Config config, Action<bool, string> update)
{
Task.Run(() => UpdateTaskRunSubscription(config, update));
Task.Run(() => UpdateTaskRunGeo(config, update));
}
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
{
await Task.Delay(60000);
Logging.SaveLog("UpdateTaskRunSubscription");
var updateHandle = new UpdateHandler();
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)
Logging.SaveLog("subscription" + msg);
});
item.updateTime = updateTime;
ConfigHandler.AddSubItem(config, item);
await Task.Delay(5000);
}
await Task.Delay(60000);
}
}
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> update)
{
var autoUpdateGeoTime = DateTime.Now;
await Task.Delay(1000 * 120);
Logging.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateHandler();
while (true)
{
var dtNow = DateTime.Now;
if (config.guiItem.autoUpdateInterval > 0)
{
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
{
updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
update(false, msg);
});
autoUpdateGeoTime = dtNow;
}
}
await Task.Delay(1000 * 3600);
}
}
}
}

View File

@@ -1,26 +1,17 @@
using DynamicData; using System.Diagnostics;
using Splat;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows;
using v2rayN.Base;
using v2rayN.Mode;
using v2rayN.Resx;
using v2rayN.Tool;
namespace v2rayN.Handler namespace ServiceLib.Handler
{ {
internal class UpdateHandle public class UpdateHandler
{ {
private Action<bool, string> _updateFunc; private Action<bool, string> _updateFunc;
private Config _config; private Config _config;
private int _timeout = 30;
public event EventHandler<ResultEventArgs> AbsoluteCompleted; private class ResultEventArgs
public class ResultEventArgs : EventArgs
{ {
public bool Success; public bool Success;
public string Msg; public string Msg;
@@ -34,37 +25,66 @@ namespace v2rayN.Handler
} }
} }
public void CheckUpdateGuiN(Config config, Action<bool, string> update, bool preRelease) public async Task CheckUpdateGuiN(Config config, Action<bool, string> update, bool preRelease)
{ {
_config = config; _config = config;
_updateFunc = update; _updateFunc = update;
var url = string.Empty; var url = string.Empty;
var fileName = string.Empty;
DownloadHandle downloadHandle = new(); DownloadHandler downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) => downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
{ {
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully); _updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(true, Utils.UrlEncode(fileName));
}
else
{
_updateFunc(false, args.Msg);
}
};
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, args.GetException().Message);
};
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, ECoreType.v2rayN));
var args = await CheckUpdateAsync(downloadHandle, ECoreType.v2rayN, preRelease);
if (args.Success)
{
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, ECoreType.v2rayN));
_updateFunc(false, args.Msg);
url = args.Url;
fileName = Utils.GetTempPath(Utils.GetGUID());
await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
}
else
{
_updateFunc(false, args.Msg);
}
}
public async Task CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
{
_config = config;
_updateFunc = update;
var url = string.Empty;
var fileName = string.Empty;
DownloadHandler downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{
if (args.Success)
{
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(false, ResUI.MsgUnpacking);
try try
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url)); _updateFunc(true, fileName);
fileName = Utils.UrlEncode(fileName);
Process process = new()
{
StartInfo = new ProcessStartInfo
{
FileName = "v2rayUpgrade.exe",
Arguments = $"\"{fileName}\"",
WorkingDirectory = Utils.StartupPath()
}
};
process.Start();
if (process.Id > 0)
{
_updateFunc(true, "");
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -80,77 +100,25 @@ namespace v2rayN.Handler
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.GetException().Message);
}; };
AbsoluteCompleted += (sender2, args) =>
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, type));
var args = await CheckUpdateAsync(downloadHandle, type, preRelease);
if (args.Success)
{ {
if (args.Success) _updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, type));
{ _updateFunc(false, args.Msg);
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "v2rayN"));
_updateFunc(false, args.Msg);
url = args.Url; url = args.Url;
_ = askToDownload(downloadHandle, url, true); fileName = Utils.GetTempPath(Utils.GetGUID());
} await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
else }
{ else
Locator.Current.GetService<NoticeHandler>()?.Enqueue(args.Msg);
_updateFunc(false, args.Msg);
}
};
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, "v2rayN"));
CheckUpdateAsync(ECoreType.v2rayN, preRelease);
}
public void CheckUpdateCore(ECoreType type, Config config, Action<bool, string> update, bool preRelease)
{
_config = config;
_updateFunc = update;
var url = string.Empty;
DownloadHandle downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) if (!args.Msg.IsNullOrEmpty())
{
_updateFunc(false, ResUI.MsgDownloadV2rayCoreSuccessfully);
_updateFunc(false, ResUI.MsgUnpacking);
try
{
_updateFunc(true, url);
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
}
}
else
{ {
_updateFunc(false, args.Msg); _updateFunc(false, args.Msg);
} }
}; }
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(true, args.GetException().Message);
};
AbsoluteCompleted += (sender2, args) =>
{
if (args.Success)
{
_updateFunc(false, string.Format(ResUI.MsgParsingSuccessfully, "Core"));
_updateFunc(false, args.Msg);
url = args.Url;
_ = askToDownload(downloadHandle, url, true);
}
else
{
Locator.Current.GetService<NoticeHandler>()?.Enqueue(args.Msg);
_updateFunc(false, args.Msg);
}
};
_updateFunc(false, string.Format(ResUI.MsgStartUpdating, "Core"));
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)
@@ -180,7 +148,7 @@ namespace v2rayN.Handler
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}"); //_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
continue; continue;
} }
if (!url.StartsWith(Global.httpsProtocol) && !url.StartsWith(Global.httpProtocol)) if (!url.StartsWith(Global.HttpsProtocol) && !url.StartsWith(Global.HttpProtocol))
{ {
continue; continue;
} }
@@ -190,7 +158,7 @@ namespace v2rayN.Handler
continue; continue;
} }
var downloadHandle = new DownloadHandle(); var downloadHandle = new DownloadHandler();
downloadHandle.Error += (sender2, args) => downloadHandle.Error += (sender2, args) =>
{ {
_updateFunc(false, $"{hashCode}{args.GetException().Message}"); _updateFunc(false, $"{hashCode}{args.GetException().Message}");
@@ -203,7 +171,7 @@ namespace v2rayN.Handler
//convert //convert
if (!Utils.IsNullOrEmpty(item.convertTarget)) if (!Utils.IsNullOrEmpty(item.convertTarget))
{ {
var subConvertUrl = string.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl; var subConvertUrl = Utils.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
url = string.Format(subConvertUrl!, Utils.UrlEncode(url)); url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
if (!url.Contains("target=")) if (!url.Contains("target="))
{ {
@@ -223,15 +191,12 @@ namespace v2rayN.Handler
//more url //more url
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx())) if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
{ {
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result)) if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result!))
{ {
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
} }
var lstUrl = new List<string> var lstUrl = item.moreUrl.TrimEx().Split(",") ?? [];
{
item.moreUrl.TrimEx().Split(",")
};
foreach (var it in lstUrl) foreach (var it in lstUrl)
{ {
var url2 = Utils.GetPunycode(it); var url2 = Utils.GetPunycode(it);
@@ -247,7 +212,7 @@ namespace v2rayN.Handler
} }
if (!Utils.IsNullOrEmpty(result2)) if (!Utils.IsNullOrEmpty(result2))
{ {
if (Utils.IsBase64String(result2)) if (Utils.IsBase64String(result2!))
{ {
result += Utils.Base64Decode(result2); result += Utils.Base64Decode(result2);
} }
@@ -266,16 +231,16 @@ 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}");
} }
int ret = ConfigHandler.AddBatchServers(ref config, result, id, true); int ret = ConfigHandler.AddBatchServers(config, result, id, true);
if (ret <= 0) if (ret <= 0)
{ {
Utils.SaveLog("FailedImportSubscription"); Logging.SaveLog("FailedImportSubscription");
Utils.SaveLog(result); Logging.SaveLog(result);
} }
_updateFunc(false, _updateFunc(false,
ret > 0 ret > 0
@@ -289,23 +254,18 @@ namespace v2rayN.Handler
}); });
} }
public void UpdateGeoFileAll(Config config, Action<bool, string> update) public async Task UpdateGeoFileAll(Config config, Action<bool, string> update)
{ {
Task.Run(async () => await UpdateGeoFile("geosite", _config, update);
{ await UpdateGeoFile("geoip", _config, update);
await UpdateGeoFile("geosite", _config, update); _updateFunc(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
await UpdateGeoFile("geoip", _config, update);
await UpdateGeoFile4Singbox("geosite", _config, false, update);
await UpdateGeoFile4Singbox("geoip", _config, true, update);
});
} }
public void RunAvailabilityCheck(Action<bool, string> update) public void RunAvailabilityCheck(Action<bool, string> update)
{ {
Task.Run(async () => Task.Run(async () =>
{ {
var time = await (new DownloadHandle()).RunAvailabilityCheck(null); var time = await (new DownloadHandler()).RunAvailabilityCheck(null);
update(false, string.Format(ResUI.TestMeOutput, time)); update(false, string.Format(ResUI.TestMeOutput, time));
}); });
@@ -313,44 +273,44 @@ namespace v2rayN.Handler
#region private #region private
private async void CheckUpdateAsync(ECoreType type, bool preRelease) private async Task<ResultEventArgs> CheckUpdateAsync(DownloadHandler downloadHandle, ECoreType type, bool preRelease)
{ {
try try
{ {
var coreInfo = LazyConfig.Instance.GetCoreInfo(type); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
string url = coreInfo.coreReleaseApiUrl; var url = coreInfo?.coreReleaseApiUrl;
var result = await (new DownloadHandle()).DownloadStringAsync(url, true, ""); var result = await downloadHandle.DownloadStringAsync(url, true, Global.AppName);
if (!Utils.IsNullOrEmpty(result)) if (!Utils.IsNullOrEmpty(result))
{ {
responseHandler(type, result, preRelease); return await ParseDownloadUrl(type, result, preRelease);
} }
else else
{ {
Utils.SaveLog("StatusCode error: " + url); return new ResultEventArgs(false, "");
return;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
_updateFunc(false, ex.Message); _updateFunc(false, ex.Message);
return new ResultEventArgs(false, ex.Message);
} }
} }
/// <summary> /// <summary>
/// 获取V2RayCore版本 /// 获取Core版本
/// </summary> /// </summary>
private SemanticVersion getCoreVersion(ECoreType type) private SemanticVersion GetCoreVersion(ECoreType type)
{ {
try try
{ {
var coreInfo = LazyConfig.Instance.GetCoreInfo(type); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
string filePath = string.Empty; string filePath = string.Empty;
foreach (string name in coreInfo.coreExes) foreach (string name in coreInfo.coreExes)
{ {
string vName = $"{name}.exe"; string vName = Utils.GetExeName(name);
vName = Utils.GetBinPath(vName, coreInfo.coreType); vName = Utils.GetBinPath(vName, coreInfo.coreType.ToString());
if (File.Exists(vName)) if (File.Exists(vName))
{ {
filePath = vName; filePath = vName;
@@ -366,7 +326,7 @@ namespace v2rayN.Handler
} }
using Process p = new(); using Process p = new();
p.StartInfo.FileName = filePath; p.StartInfo.FileName = filePath.AppendQuotes();
p.StartInfo.Arguments = coreInfo.versionArg; p.StartInfo.Arguments = coreInfo.versionArg;
p.StartInfo.WorkingDirectory = Utils.StartupPath(); p.StartInfo.WorkingDirectory = Utils.StartupPath();
p.StartInfo.UseShellExecute = false; p.StartInfo.UseShellExecute = false;
@@ -388,6 +348,7 @@ namespace v2rayN.Handler
case ECoreType.clash: case ECoreType.clash:
case ECoreType.clash_meta: case ECoreType.clash_meta:
case ECoreType.mihomo:
version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value; version = Regex.Match(echo, $"v[0-9.]+").Groups[0].Value;
break; break;
@@ -399,26 +360,25 @@ namespace v2rayN.Handler
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
_updateFunc(false, ex.Message); _updateFunc(false, ex.Message);
return new SemanticVersion(""); return new SemanticVersion("");
} }
} }
private void responseHandler(ECoreType type, string gitHubReleaseApi, bool preRelease) private async Task<ResultEventArgs> ParseDownloadUrl(ECoreType type, string gitHubReleaseApi, bool preRelease)
{ {
try try
{ {
var gitHubReleases = Utils.FromJson<List<GitHubRelease>>(gitHubReleaseApi); var gitHubReleases = JsonUtils.Deserialize<List<GitHubRelease>>(gitHubReleaseApi);
var gitHubRelease = preRelease ? gitHubReleases!.First() : gitHubReleases!.First(r => r.Prerelease == false); var gitHubRelease = preRelease ? gitHubReleases?.First() : gitHubReleases?.First(r => r.Prerelease == false);
var version = new SemanticVersion(gitHubRelease!.TagName); var version = new SemanticVersion(gitHubRelease?.TagName!);
var body = gitHubRelease!.Body; var body = gitHubRelease?.Body;
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
SemanticVersion curVersion; SemanticVersion curVersion;
string message; string message;
string url; string? url;
switch (type) switch (type)
{ {
case ECoreType.v2fly: case ECoreType.v2fly:
@@ -426,88 +386,32 @@ namespace v2rayN.Handler
case ECoreType.Xray: case ECoreType.Xray:
case ECoreType.v2fly_v5: case ECoreType.v2fly_v5:
{ {
curVersion = getCoreVersion(type); curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v")); message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
string osBit = "64"; url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
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.ToVersionString("v"), osBit);
break; break;
} }
case ECoreType.clash: case ECoreType.clash:
case ECoreType.clash_meta: case ECoreType.clash_meta:
case ECoreType.mihomo:
{ {
curVersion = getCoreVersion(type); curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion); message = string.Format(ResUI.IsLatestCore, type, curVersion);
switch (RuntimeInformation.ProcessArchitecture) url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"));
{
case Architecture.Arm64:
url = coreInfo.coreDownloadUrlArm64;
break;
case Architecture.X86:
url = coreInfo.coreDownloadUrl32;
break;
default:
url = coreInfo.coreDownloadUrl64;
break;
}
url = string.Format(url, version.ToVersionString("v"));
break; break;
} }
case ECoreType.sing_box: case ECoreType.sing_box:
{ {
curVersion = getCoreVersion(type); curVersion = GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v")); message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
switch (RuntimeInformation.ProcessArchitecture) url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"), 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.ToVersionString("v"), version);
break; break;
} }
case ECoreType.v2rayN: case ECoreType.v2rayN:
{ {
curVersion = new SemanticVersion(FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString()); curVersion = new SemanticVersion(Utils.GetVersionInfo());
message = string.Format(ResUI.IsLatestN, type, curVersion); message = string.Format(ResUI.IsLatestN, type, curVersion);
switch (RuntimeInformation.ProcessArchitecture) url = string.Format(GetUrlFromCore(coreInfo), version);
{
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:
@@ -516,46 +420,52 @@ namespace v2rayN.Handler
if (curVersion >= version && version != new SemanticVersion(0, 0, 0)) if (curVersion >= version && version != new SemanticVersion(0, 0, 0))
{ {
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message)); return new ResultEventArgs(false, message);
return;
} }
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(true, body, url)); return new ResultEventArgs(true, body, url);
} }
catch (Exception ex) catch (Exception ex)
{ {
Utils.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
_updateFunc(false, ex.Message); _updateFunc(false, ex.Message);
return new ResultEventArgs(false, ex.Message);
} }
} }
private async Task askToDownload(DownloadHandle downloadHandle, string url, bool blAsk) private string? GetUrlFromCore(CoreInfo? coreInfo)
{ {
bool blDownload = false; if (Utils.IsWindows())
if (blAsk)
{ {
if (UI.ShowYesNo(string.Format(ResUI.DownloadYesNo, url)) == MessageBoxResult.Yes) return RuntimeInformation.ProcessArchitecture switch
{ {
blDownload = true; Architecture.Arm64 => coreInfo?.coreDownloadUrlArm64,
} Architecture.X86 => coreInfo?.coreDownloadUrl32,
Architecture.X64 => coreInfo?.coreDownloadUrl64,
_ => null,
};
} }
else else if (Utils.IsLinux())
{ {
blDownload = true; return RuntimeInformation.ProcessArchitecture switch
} {
if (blDownload) Architecture.Arm64 => coreInfo?.coreDownloadUrlLinuxArm64,
{ Architecture.X86 => coreInfo?.coreDownloadUrlLinux32,
await downloadHandle.DownloadFileAsync(url, true, 600); Architecture.X64 => coreInfo?.coreDownloadUrlLinux64,
_ => null,
};
} }
return null;
} }
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> update) private async Task 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);
var fileName = Utils.GetTempPath(Utils.GetGUID());
DownloadHandle downloadHandle = new(); DownloadHandler downloadHandle = new();
downloadHandle.UpdateCompleted += (sender2, args) => downloadHandle.UpdateCompleted += (sender2, args) =>
{ {
if (args.Success) if (args.Success)
@@ -564,14 +474,8 @@ namespace v2rayN.Handler
try try
{ {
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
if (File.Exists(fileName)) if (File.Exists(fileName))
{ {
//Global.coreTypes.ForEach(it =>
//{
// string targetPath = Utils.GetBinPath($"{geoName}.dat", (ECoreType)Enum.Parse(typeof(ECoreType), it));
// File.Copy(fileName, targetPath, true);
//});
string targetPath = Utils.GetBinPath($"{geoName}.dat"); string targetPath = Utils.GetBinPath($"{geoName}.dat");
File.Copy(fileName, targetPath, true); File.Copy(fileName, targetPath, true);
@@ -593,55 +497,8 @@ namespace v2rayN.Handler
{ {
_updateFunc(false, args.GetException().Message); _updateFunc(false, args.GetException().Message);
}; };
await askToDownload(downloadHandle, url, false);
}
private async Task UpdateGeoFile4Singbox(string geoName, Config config, bool needStop, Action<bool, string> update) await downloadHandle.DownloadFileAsync(url, fileName, true, _timeout);
{
_config = config;
_updateFunc = update;
var url = string.Format(Global.singboxGeoUrl, geoName);
DownloadHandle downloadHandle = new();
downloadHandle.UpdateCompleted += async (sender2, args) =>
{
if (args.Success)
{
_updateFunc(false, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, geoName));
var coreHandler = Locator.Current.GetService<CoreHandler>();
try
{
if (needStop)
{
coreHandler?.CoreStop();
await Task.Delay(3000);
}
string fileName = Utils.GetTempPath(Utils.GetDownloadFileName(url));
if (File.Exists(fileName))
{
string targetPath = Utils.GetConfigPath($"{geoName}.db");
File.Copy(fileName, targetPath, true);
File.Delete(fileName);
}
if (needStop) coreHandler?.LoadCore();
}
catch (Exception ex)
{
_updateFunc(false, ex.Message);
}
}
else
{
_updateFunc(false, args.Msg);
}
};
downloadHandle.Error += (sender2, args) =>
{
_updateFunc(false, args.GetException().Message);
};
await askToDownload(downloadHandle, url, false);
} }
#endregion private #endregion private

View File

@@ -0,0 +1,11 @@
namespace ServiceLib.Models
{
public class CheckUpdateItem
{
public bool? isSelected { get; set; }
public string coreType { get; set; }
public string? remarks { get; set; }
public string? fileName { get; set; }
public bool? isFinished { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
namespace ServiceLib.Models
{
public class ClashConnectionModel
{
public string id { get; set; }
public string network { get; set; }
public string type { get; set; }
public string host { get; set; }
public ulong upload { get; set; }
public ulong download { get; set; }
public string uploadTraffic { get; set; }
public string downloadTraffic { get; set; }
public double time { get; set; }
public string elapsed { get; set; }
public string chain { get; set; }
}
}

View File

@@ -0,0 +1,37 @@
namespace ServiceLib.Models
{
public class ClashConnections
{
public ulong downloadTotal { get; set; }
public ulong uploadTotal { get; set; }
public List<ConnectionItem>? connections { get; set; }
}
public class ConnectionItem
{
public string id { get; set; } = string.Empty;
public MetadataItem metadata { get; set; }
public ulong upload { get; set; }
public ulong download { get; set; }
public DateTime start { get; set; }
public List<string>? chains { get; set; }
public string rule { get; set; }
public string rulePayload { get; set; }
}
public class MetadataItem
{
public string network { get; set; }
public string type { get; set; }
public string sourceIP { get; set; }
public string destinationIP { get; set; }
public string sourcePort { get; set; }
public string destinationPort { get; set; }
public string host { get; set; }
public string nsMode { get; set; }
public object uid { get; set; }
public string process { get; set; }
public string processPath { get; set; }
public string remoteDestination { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using static ServiceLib.Models.ClashProxies;
namespace ServiceLib.Models
{
public class ClashProviders
{
public Dictionary<String, ProvidersItem> providers { get; set; }
public class ProvidersItem
{
public string name { get; set; }
public ProxiesItem[] proxies { get; set; }
public string type { get; set; }
public string vehicleType { get; set; }
}
}
}

View File

@@ -0,0 +1,24 @@
namespace ServiceLib.Models
{
public class ClashProxies
{
public Dictionary<String, ProxiesItem> proxies { get; set; }
public class ProxiesItem
{
public string[] all { get; set; }
public List<HistoryItem> history { get; set; }
public string name { get; set; }
public string type { get; set; }
public bool udp { get; set; }
public string now { get; set; }
public int delay { get; set; }
}
public class HistoryItem
{
public string time { get; set; }
public int delay { get; set; }
}
}
}

View File

@@ -0,0 +1,18 @@
namespace ServiceLib.Models
{
[Serializable]
public class ClashProxyModel
{
public string name { get; set; }
public string type { get; set; }
public string now { get; set; }
public int delay { get; set; }
public string delayName { get; set; }
public bool isActive { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
public class ComboItem public class ComboItem
{ {

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
/// <summary> /// <summary>
/// 本软件配置文件实体类 /// 本软件配置文件实体类
@@ -10,10 +10,24 @@
public string indexId { get; set; } public string indexId { get; set; }
public string subIndexId { get; set; } public string subIndexId { get; set; }
public ESysProxyType sysProxyType { get; set; }
public string systemProxyExceptions { get; set; } public string systemProxyExceptions { get; set; }
public string systemProxyAdvancedProtocol { get; set; } public string systemProxyAdvancedProtocol { get; set; }
public ECoreType runningCoreType { get; set; }
public bool IsRunningCore(ECoreType type)
{
if (type == ECoreType.Xray && runningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5 or ECoreType.SagerNet)
{
return true;
}
if (type == ECoreType.clash && runningCoreType is ECoreType.sing_box or ECoreType.clash or ECoreType.clash_meta or ECoreType.mihomo)
{
return true;
}
return false;
}
#endregion property #endregion property
#region other entities #region other entities
@@ -24,11 +38,15 @@
public GrpcItem grpcItem { get; set; } public GrpcItem grpcItem { get; set; }
public RoutingBasicItem routingBasicItem { get; set; } public RoutingBasicItem routingBasicItem { get; set; }
public GUIItem guiItem { get; set; } public GUIItem guiItem { get; set; }
public MsgUIItem msgUIItem { 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 SpeedTestItem speedTestItem { get; set; }
public Mux4RayItem mux4RayItem { get; set; }
public Mux4SboxItem mux4SboxItem { get; set; } public Mux4SboxItem mux4SboxItem { get; set; }
public HysteriaItem hysteriaItem { get; set; } public HysteriaItem hysteriaItem { get; set; }
public ClashUIItem clashUIItem { get; set; }
public SystemProxyItem systemProxyItem { get; set; }
public List<InItem> inbound { get; set; } public List<InItem> inbound { get; set; }
public List<KeyEventItem> globalHotkeys { get; set; } public List<KeyEventItem> globalHotkeys { get; set; }
public List<CoreTypeItem> coreTypeItem { get; set; } public List<CoreTypeItem> coreTypeItem { get; set; }

View File

@@ -1,6 +1,4 @@
using System.Windows.Input; namespace ServiceLib.Models
namespace v2rayN.Mode
{ {
[Serializable] [Serializable]
public class CoreBasicItem public class CoreBasicItem
@@ -31,6 +29,10 @@ namespace v2rayN.Mode
/// 默认用户代理 /// 默认用户代理
/// </summary> /// </summary>
public string defUserAgent { get; set; } public string defUserAgent { get; set; }
public bool enableFragment { get; set; }
public bool enableCacheFile4Sbox { get; set; } = true;
} }
[Serializable] [Serializable]
@@ -43,8 +45,8 @@ namespace v2rayN.Mode
public bool udpEnabled { get; set; } public bool udpEnabled { get; set; }
public bool sniffingEnabled { get; set; } = true; public bool sniffingEnabled { get; set; } = true;
public List<string>? destOverride { get; set; } = ["http", "tls"];
public bool routeOnly { get; set; } public bool routeOnly { get; set; }
public bool allowLANConn { get; set; } public bool allowLANConn { get; set; }
public bool newPort4LAN { get; set; } public bool newPort4LAN { get; set; }
@@ -105,14 +107,23 @@ namespace v2rayN.Mode
public bool enableLog { get; set; } = true; public bool enableLog { get; set; } = true;
} }
[Serializable]
public class MsgUIItem
{
public string? mainMsgFilter { get; set; }
public bool? autoRefresh { get; set; }
}
[Serializable] [Serializable]
public class UIItem public class UIItem
{ {
public bool enableAutoAdjustMainLvColWidth { get; set; } public bool enableAutoAdjustMainLvColWidth { get; set; }
public bool enableUpdateSubOnlyRemarksExist { get; set; }
public double mainWidth { get; set; } public double mainWidth { get; set; }
public double mainHeight { get; set; } public double mainHeight { get; set; }
public double mainGirdHeight1 { get; set; } public double mainGirdHeight1 { get; set; }
public double mainGirdHeight2 { get; set; } public double mainGirdHeight2 { get; set; }
public EGirdOrientation mainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
public bool colorModeDark { get; set; } public bool colorModeDark { get; set; }
public bool followSystemTheme { get; set; } public bool followSystemTheme { get; set; }
public string? colorPrimaryName { get; set; } public string? colorPrimaryName { get; set; }
@@ -121,10 +132,9 @@ namespace v2rayN.Mode
public int currentFontSize { 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; }
public string mainMsgFilter { get; set; }
public bool showTrayTip { get; set; }
public List<ColumnItem> mainColumnItem { get; set; } public List<ColumnItem> mainColumnItem { get; set; }
public bool showInTaskbar { get; set; }
} }
[Serializable] [Serializable]
@@ -145,7 +155,7 @@ namespace v2rayN.Mode
public bool Shift { get; set; } public bool Shift { get; set; }
public Key? KeyCode { get; set; } public int? KeyCode { get; set; }
} }
[Serializable] [Serializable]
@@ -164,6 +174,7 @@ namespace v2rayN.Mode
public string stack { get; set; } public string stack { get; set; }
public int mtu { get; set; } public int mtu { get; set; }
public bool enableExInbound { get; set; } public bool enableExInbound { get; set; }
public bool enableIPv6Address { get; set; }
} }
[Serializable] [Serializable]
@@ -177,13 +188,8 @@ namespace v2rayN.Mode
[Serializable] [Serializable]
public class RoutingBasicItem public class RoutingBasicItem
{ {
/// <summary>
/// 域名解析策略
/// </summary>
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
public string domainStrategy4Singbox { get; set; } public string domainStrategy4Singbox { get; set; }
public string domainMatcher { get; set; } public string domainMatcher { get; set; }
public string routingIndexId { get; set; } public string routingIndexId { get; set; }
public bool enableRoutingAdvanced { get; set; } public bool enableRoutingAdvanced { get; set; }
@@ -197,14 +203,20 @@ namespace v2rayN.Mode
public int Index { get; set; } public int Index { get; set; }
} }
[Serializable]
public class Mux4RayItem
{
public int? concurrency { get; set; }
public int? xudpConcurrency { get; set; }
public string? xudpProxyUDP443 { get; set; }
}
[Serializable] [Serializable]
public class Mux4SboxItem public class Mux4SboxItem
{ {
public string protocol { get; set; } public string protocol { get; set; }
public int max_connections { get; set; } public int max_connections { get; set; }
public int min_streams { get; set; } public bool? padding { get; set; }
public int max_streams { get; set; }
public bool padding { get; set; }
} }
[Serializable] [Serializable]
@@ -213,4 +225,27 @@ namespace v2rayN.Mode
public int up_mbps { get; set; } public int up_mbps { get; set; }
public int down_mbps { get; set; } public int down_mbps { get; set; }
} }
[Serializable]
public class ClashUIItem
{
public ERuleMode ruleMode { get; set; }
public bool enableIPv6 { get; set; }
public bool enableMixinContent { get; set; }
public int proxiesSorting { get; set; }
public bool proxiesAutoRefresh { get; set; }
public int proxiesAutoDelayTestInterval { get; set; } = 10;
public int connectionsSorting { get; set; }
public bool connectionsAutoRefresh { get; set; }
public int connectionsRefreshInterval { get; set; } = 2;
}
[Serializable]
public class SystemProxyItem
{
public ESysProxyType sysProxyType { get; set; }
public string systemProxyExceptions { get; set; }
public bool notProxyLocalAddress { get; set; } = true;
public string systemProxyAdvancedProtocol { get; set; }
}
} }

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class CoreInfo public class CoreInfo
@@ -18,6 +18,9 @@
public string coreDownloadUrl64 { get; set; } public string coreDownloadUrl64 { get; set; }
public string coreDownloadUrlArm64 { get; set; } public string coreDownloadUrlArm64 { get; set; }
public string? coreDownloadUrlLinux32 { get; set; }
public string? coreDownloadUrlLinux64 { get; set; }
public string? coreDownloadUrlLinuxArm64 { get; set; }
public string match { get; set; } public string match { get; set; }
public string versionArg { get; set; } public string versionArg { get; set; }

View File

@@ -1,6 +1,6 @@
using SQLite; using SQLite;
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class DNSItem public class DNSItem
@@ -15,5 +15,6 @@ namespace v2rayN.Mode
public string? normalDNS { get; set; } public string? normalDNS { get; set; }
public string? tunDNS { get; set; } public string? tunDNS { get; set; }
public string? domainStrategy4Freedom { get; set; } public string? domainStrategy4Freedom { get; set; }
public string? domainDNSAddress { get; set; }
} }
} }

View File

@@ -0,0 +1,68 @@
using System.Text.Json.Serialization;
namespace ServiceLib.Models
{
public class GitHubReleaseAsset
{
[JsonPropertyName("url")] public string Url { get; set; }
[JsonPropertyName("id")] public int Id { get; set; }
[JsonPropertyName("node_id")] public string NodeId { get; set; }
[JsonPropertyName("name")] public string Name { get; set; }
[JsonPropertyName("label")] public object Label { get; set; }
[JsonPropertyName("content_type")] public string ContentType { get; set; }
[JsonPropertyName("state")] public string State { get; set; }
[JsonPropertyName("size")] public int Size { get; set; }
[JsonPropertyName("download_count")] public int DownloadCount { get; set; }
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
[JsonPropertyName("updated_at")] public DateTime UpdatedAt { get; set; }
[JsonPropertyName("browser_download_url")] public string BrowserDownloadUrl { get; set; }
}
public class GitHubRelease
{
[JsonPropertyName("url")] public string Url { get; set; }
[JsonPropertyName("assets_url")] public string AssetsUrl { get; set; }
[JsonPropertyName("upload_url")] public string UploadUrl { get; set; }
[JsonPropertyName("html_url")] public string HtmlUrl { get; set; }
[JsonPropertyName("id")] public int Id { get; set; }
[JsonPropertyName("node_id")] public string NodeId { get; set; }
[JsonPropertyName("tag_name")] public string TagName { get; set; }
[JsonPropertyName("target_commitish")] public string TargetCommitish { get; set; }
[JsonPropertyName("name")] public string Name { get; set; }
[JsonPropertyName("draft")] public bool Draft { get; set; }
[JsonPropertyName("prerelease")] public bool Prerelease { get; set; }
[JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; }
[JsonPropertyName("published_at")] public DateTime PublishedAt { get; set; }
[JsonPropertyName("assets")] public List<GitHubReleaseAsset> Assets { get; set; }
[JsonPropertyName("tarball_url")] public string TarballUrl { get; set; }
[JsonPropertyName("zipball_url")] public string ZipballUrl { get; set; }
[JsonPropertyName("body")] public string Body { get; set; }
}
}

View File

@@ -1,6 +1,6 @@
using SQLite; using SQLite;
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class ProfileExItem public class ProfileExItem

View File

@@ -1,7 +1,6 @@
using SQLite; using SQLite;
using v2rayN.Base;
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class ProfileItem public class ProfileItem
@@ -48,17 +47,12 @@ namespace v2rayN.Mode
} }
switch (configType) switch (configType)
{ {
case EConfigType.VMess: case EConfigType.Custom:
case EConfigType.Shadowsocks: summary += string.Format("[{1}]{0}", remarks, coreType.ToString());
case EConfigType.Socks:
case EConfigType.VLESS:
case EConfigType.Trojan:
case EConfigType.Hysteria2:
summary += string.Format("{0}({1}:{2})", remarks, addr, port);
break; break;
default: default:
summary += string.Format("{0}", remarks); summary += string.Format("{0}({1}:{2})", remarks, addr, port);
break; break;
} }
return summary; return summary;
@@ -78,7 +72,7 @@ namespace v2rayN.Mode
public string GetNetwork() public string GetNetwork()
{ {
if (Utils.IsNullOrEmpty(network) || !Global.networks.Contains(network)) if (Utils.IsNullOrEmpty(network) || !Global.Networks.Contains(network))
{ {
return Global.DefaultNetwork; return Global.DefaultNetwork;
} }
@@ -184,7 +178,7 @@ namespace v2rayN.Mode
public ECoreType? coreType { get; set; } public ECoreType? coreType { get; set; }
public int preSocksPort { get; set; } public int? preSocksPort { get; set; }
public string fingerprint { get; set; } public string fingerprint { get; set; }

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class ProfileItemModel : ProfileItem public class ProfileItemModel : ProfileItem

View File

@@ -1,6 +1,6 @@
using SQLite; using SQLite;
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class RoutingItem public class RoutingItem
@@ -15,6 +15,7 @@ namespace v2rayN.Mode
public bool enabled { get; set; } = true; public bool enabled { get; set; } = true;
public bool locked { get; set; } public bool locked { get; set; }
public string customIcon { get; set; } public string customIcon { get; set; }
public string customRulesetPath4Singbox { get; set; }
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
public string domainStrategy4Singbox { get; set; } public string domainStrategy4Singbox { get; set; }
public int sort { get; set; } public int sort { get; set; }

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class RoutingItemModel : RoutingItem public class RoutingItemModel : RoutingItem

View File

@@ -0,0 +1,26 @@
namespace ServiceLib.Models
{
[Serializable]
public class RulesItem
{
public string id { get; set; }
public string? type { get; set; }
public string? port { get; set; }
public string? network { get; set; }
public List<string>? inboundTag { get; set; }
public string? outboundTag { get; set; }
public List<string>? ip { get; set; }
public List<string>? domain { get; set; }
public List<string>? protocol { get; set; }
public List<string>? process { get; set; }
public bool enabled { get; set; } = true;
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class RulesItemModel : RulesItem public class RulesItemModel : RulesItem

View File

@@ -1,7 +1,7 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
internal class ServerSpeedItem : ServerStatItem public class ServerSpeedItem : ServerStatItem
{ {
public long proxyUp public long proxyUp
{ {

View File

@@ -1,6 +1,6 @@
using SQLite; using SQLite;
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class ServerStatItem public class ServerStatItem

View File

@@ -1,7 +1,7 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
internal class ServerTestItem public class ServerTestItem
{ {
public string indexId { get; set; } public string indexId { get; set; }
public string address { get; set; } public string address { get; set; }

View File

@@ -1,13 +1,13 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
public class SingboxConfig public class SingboxConfig
{ {
public Log4Sbox log { get; set; } public Log4Sbox log { get; set; }
public object dns { get; set; } public Dns4Sbox? dns { get; set; }
public List<Inbound4Sbox> inbounds { get; set; } public List<Inbound4Sbox> inbounds { get; set; }
public List<Outbound4Sbox> outbounds { get; set; } public List<Outbound4Sbox> outbounds { get; set; }
public Route4Sbox route { get; set; } public Route4Sbox route { get; set; }
public Experimental4Sbox experimental { get; set; } public Experimental4Sbox? experimental { get; set; }
} }
public class Log4Sbox public class Log4Sbox
@@ -15,7 +15,7 @@
public bool? disabled { get; set; } public bool? disabled { get; set; }
public string level { get; set; } public string level { get; set; }
public string output { get; set; } public string output { get; set; }
public bool timestamp { get; set; } public bool? timestamp { get; set; }
} }
public class Dns4Sbox public class Dns4Sbox
@@ -28,6 +28,7 @@
public bool? disable_expire { get; set; } public bool? disable_expire { get; set; }
public bool? independent_cache { get; set; } public bool? independent_cache { get; set; }
public bool? reverse_mapping { get; set; } public bool? reverse_mapping { get; set; }
public string? client_subnet { get; set; }
public Fakeip4Sbox? fakeip { get; set; } public Fakeip4Sbox? fakeip { get; set; }
} }
@@ -35,19 +36,24 @@
{ {
public bool? auto_detect_interface { get; set; } public bool? auto_detect_interface { get; set; }
public List<Rule4Sbox> rules { get; set; } public List<Rule4Sbox> rules { get; set; }
public List<Ruleset4Sbox>? rule_set { get; set; }
} }
[Serializable] [Serializable]
public class Rule4Sbox public class Rule4Sbox
{ {
public string outbound { get; set; } public string? outbound { get; set; }
public string server { get; set; } public string? server { get; set; }
public bool? disable_cache { get; set; } public bool? disable_cache { get; set; }
public string? type { get; set; }
public string? mode { get; set; }
public bool? ip_is_private { get; set; }
public string? client_subnet { get; set; }
public bool? invert { get; set; }
public string? clash_mode { get; set; }
public List<string>? inbound { get; set; } public List<string>? inbound { get; set; }
public List<string>? protocol { get; set; } public List<string>? protocol { get; set; }
public string type { get; set; } public List<string>? network { get; set; }
public string mode { get; set; }
public string network { get; set; }
public List<int>? port { get; set; } public List<int>? port { get; set; }
public List<string>? port_range { get; set; } public List<string>? port_range { get; set; }
public List<string>? geosite { get; set; } public List<string>? geosite { get; set; }
@@ -58,8 +64,9 @@
public List<string>? geoip { get; set; } public List<string>? geoip { get; set; }
public List<string>? ip_cidr { get; set; } public List<string>? ip_cidr { get; set; }
public List<string>? source_ip_cidr { get; set; } public List<string>? source_ip_cidr { get; set; }
public List<string>? process_name { get; set; } public List<string>? process_name { get; set; }
public List<string>? rule_set { get; set; }
public List<Rule4Sbox>? rules { get; set; }
} }
[Serializable] [Serializable]
@@ -72,7 +79,7 @@
public string? domain_strategy { get; set; } public string? domain_strategy { get; set; }
public string interface_name { get; set; } public string interface_name { get; set; }
public string inet4_address { get; set; } public string inet4_address { get; set; }
public string inet6_address { get; set; } public string? inet6_address { get; set; }
public int? mtu { get; set; } public int? mtu { get; set; }
public bool? auto_route { get; set; } public bool? auto_route { get; set; }
public bool? strict_route { get; set; } public bool? strict_route { get; set; }
@@ -93,7 +100,7 @@
{ {
public string type { get; set; } public string type { get; set; }
public string tag { get; set; } public string tag { get; set; }
public string server { get; set; } public string? server { get; set; }
public int? server_port { get; set; } public int? server_port { get; set; }
public string uuid { get; set; } public string uuid { get; set; }
public string security { get; set; } public string security { get; set; }
@@ -105,16 +112,27 @@
public int? recv_window_conn { get; set; } public int? recv_window_conn { get; set; }
public int? recv_window { get; set; } public int? recv_window { get; set; }
public bool? disable_mtu_discovery { get; set; } public bool? disable_mtu_discovery { get; set; }
public string detour { get; set; } public string? detour { get; set; }
public string method { get; set; } public string method { get; set; }
public string username { get; set; } public string username { get; set; }
public string password { get; set; } public string password { get; set; }
public string congestion_control { get; set; }
public string? version { get; set; } public string? version { get; set; }
public string? network { get; set; } public string? network { get; set; }
public string packet_encoding { get; set; } public string? packet_encoding { get; set; }
public Tls4Sbox tls { get; set; } public string[]? local_address { get; set; }
public Multiplex4Sbox multiplex { get; set; } public string? private_key { get; set; }
public Transport4Sbox transport { get; set; } public string? peer_public_key { get; set; }
public int[]? reserved { get; set; }
public int? mtu { get; set; }
public string? plugin { get; set; }
public string? plugin_opts { get; set; }
public Tls4Sbox? tls { get; set; }
public Multiplex4Sbox? multiplex { get; set; }
public Transport4Sbox? transport { get; set; }
public HyObfs4Sbox? obfs { get; set; }
public List<string>? outbounds { get; set; }
public bool? interrupt_exist_connections { get; set; }
} }
public class Tls4Sbox public class Tls4Sbox
@@ -132,9 +150,7 @@
public bool enabled { get; set; } public bool enabled { get; set; }
public string protocol { get; set; } public string protocol { get; set; }
public int max_connections { get; set; } public int max_connections { get; set; }
public int min_streams { get; set; } public bool? padding { get; set; }
public int max_streams { get; set; }
public bool padding { get; set; }
} }
public class Utls4Sbox public class Utls4Sbox
@@ -152,14 +168,14 @@
public class Transport4Sbox public class Transport4Sbox
{ {
public string type { get; set; } public string? type { get; set; }
public List<string>? host { get; set; } public object? host { get; set; }
public string? path { get; set; } public string? path { get; set; }
public Headers4Sbox? headers { get; set; } public Headers4Sbox? headers { get; set; }
public string service_name { get; set; } public string? service_name { get; set; }
public string idle_timeout { get; set; } public string? idle_timeout { get; set; }
public string ping_timeout { get; set; } public string? ping_timeout { get; set; }
public bool? permit_without_stream { get; set; } public bool? permit_without_stream { get; set; }
} }
@@ -168,19 +184,28 @@
public string? Host { get; set; } public string? Host { get; set; }
} }
public class HyObfs4Sbox
{
public string? type { get; set; }
public string? password { get; set; }
}
public class Server4Sbox public class Server4Sbox
{ {
public string tag { get; set; } public string? tag { get; set; }
public string address { get; set; } public string? address { get; set; }
public string address_resolver { get; set; } public string? address_resolver { get; set; }
public string strategy { get; set; } public string? address_strategy { get; set; }
public string detour { get; set; } public string? strategy { get; set; }
public string? detour { get; set; }
public string? client_subnet { get; set; }
} }
public class Experimental4Sbox public class Experimental4Sbox
{ {
public V2ray_Api4Sbox v2ray_api { get; set; } public CacheFile4Sbox? cache_file { get; set; }
public Clash_Api4Sbox clash_api { get; set; } public V2ray_Api4Sbox? v2ray_api { get; set; }
public Clash_Api4Sbox? clash_api { get; set; }
} }
public class V2ray_Api4Sbox public class V2ray_Api4Sbox
@@ -191,8 +216,8 @@
public class Clash_Api4Sbox public class Clash_Api4Sbox
{ {
public string external_controller { get; set; } public string? external_controller { get; set; }
public bool store_selected { get; set; } public bool? store_selected { get; set; }
} }
public class Stats4Sbox public class Stats4Sbox
@@ -209,4 +234,23 @@
public string inet4_range { get; set; } public string inet4_range { get; set; }
public string inet6_range { get; set; } public string inet6_range { get; set; }
} }
public class CacheFile4Sbox
{
public bool enabled { get; set; }
public string? path { get; set; }
public string? cache_id { get; set; }
public bool? store_fakeip { get; set; }
}
public class Ruleset4Sbox
{
public string? tag { get; set; }
public string? type { get; set; }
public string? format { get; set; }
public string? path { get; set; }
public string? url { get; set; }
public string? download_detour { get; set; }
public string? update_interval { get; set; }
}
} }

View File

@@ -0,0 +1,12 @@
namespace ServiceLib.Models
{
[Serializable]
public class SpeedTestResult
{
public string? IndexId { get; set; }
public string? Delay { get; set; }
public string? Speed { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
public class SsSIP008 public class SsSIP008
{ {

View File

@@ -1,6 +1,6 @@
using SQLite; using SQLite;
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class SubItem public class SubItem
@@ -27,5 +27,11 @@ namespace v2rayN.Mode
public long updateTime { get; set; } public long updateTime { get; set; }
public string? convertTarget { get; set; } public string? convertTarget { get; set; }
public string? prevProfile { get; set; }
public string? nextProfile { get; set; }
public int? preSocksPort { get; set; }
} }
} }

View File

@@ -1,6 +1,6 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
internal class SysproxyConfig public class SysProxyConfig
{ {
public bool UserSettingsRecorded; public bool UserSettingsRecorded;
public string Flags; public string Flags;
@@ -8,7 +8,7 @@
public string BypassList; public string BypassList;
public string PacUrl; public string PacUrl;
public SysproxyConfig() public SysProxyConfig()
{ {
UserSettingsRecorded = false; UserSettingsRecorded = false;
Flags = "1"; Flags = "1";

View File

@@ -1,13 +1,17 @@
using Newtonsoft.Json; using System.Text.Json.Serialization;
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
/// <summary> /// <summary>
/// v2ray配置文件实体类 /// v2ray配置文件实体类 例子SampleConfig.txt
/// 例子SampleConfig.txt
/// </summary> /// </summary>
public class V2rayConfig public class V2rayConfig
{ {
/// <summary>
/// Properties that do not belong to Ray
/// </summary>
public string? remarks { get; set; }
/// <summary> /// <summary>
/// 日志配置 /// 日志配置
/// </summary> /// </summary>
@@ -32,7 +36,7 @@ namespace v2rayN.Mode
public API4Ray api { get; set; } public API4Ray api { get; set; }
/// </summary> /// </summary>
public Policy4Ray policy; public Policy4Ray policy { get; set; }
/// <summary> /// <summary>
/// DNS 配置 /// DNS 配置
@@ -56,13 +60,13 @@ namespace v2rayN.Mode
public class Policy4Ray public class Policy4Ray
{ {
public SystemPolicy4Ray system; public SystemPolicy4Ray system { get; set; }
} }
public class SystemPolicy4Ray public class SystemPolicy4Ray
{ {
public bool statsOutboundUplink; public bool statsOutboundUplink { get; set; }
public bool statsOutboundDownlink; public bool statsOutboundDownlink { get; set; }
} }
public class Log4Ray public class Log4Ray
@@ -191,7 +195,7 @@ namespace v2rayN.Mode
public class Sniffing4Ray public class Sniffing4Ray
{ {
public bool enabled { get; set; } public bool enabled { get; set; }
public List<string> destOverride { get; set; } public List<string>? destOverride { get; set; }
public bool routeOnly { get; set; } public bool routeOnly { get; set; }
} }
@@ -228,7 +232,7 @@ namespace v2rayN.Mode
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<VnextItem4Ray> vnext { get; set; } public List<VnextItem4Ray>? vnext { get; set; }
/// <summary> /// <summary>
/// ///
@@ -249,6 +253,8 @@ namespace v2rayN.Mode
/// ///
/// </summary> /// </summary>
public int? userLevel { get; set; } public int? userLevel { get; set; }
public FragmentItem4Ray? fragment { get; set; }
} }
public class VnextItem4Ray public class VnextItem4Ray
@@ -284,17 +290,17 @@ namespace v2rayN.Mode
/// <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>
/// ///
@@ -304,7 +310,7 @@ namespace v2rayN.Mode
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int level { get; set; } public int? level { get; set; }
/// <summary> /// <summary>
/// trojan /// trojan
@@ -332,20 +338,15 @@ namespace v2rayN.Mode
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int level { get; set; } public int? level { get; set; }
} }
public class Mux4Ray public class Mux4Ray
{ {
/// <summary>
///
/// </summary>
public bool enabled { get; set; } public bool enabled { get; set; }
public int? concurrency { get; set; }
/// <summary> public int? xudpConcurrency { get; set; }
/// public string? xudpProxyUDP443 { get; set; }
/// </summary>
public int concurrency { get; set; }
} }
public class Response4Ray public class Response4Ray
@@ -364,6 +365,12 @@ namespace v2rayN.Mode
public List<string> servers { get; set; } public List<string> servers { get; set; }
} }
public class DnsServer4Ray
{
public string? address { get; set; }
public List<string>? domains { get; set; }
}
public class Routing4Ray public class Routing4Ray
{ {
/// <summary> /// <summary>
@@ -374,30 +381,47 @@ namespace v2rayN.Mode
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string domainMatcher { get; set; } public string? domainMatcher { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<RulesItem4Ray> rules { get; set; } public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; }
} }
[Serializable] [Serializable]
public class RulesItem4Ray public class RulesItem4Ray
{ {
public string type { get; set; } public string? type { get; set; }
public string port { get; set; } public string? port { get; set; }
public string? network { get; set; }
public List<string> inboundTag { get; set; } public List<string>? inboundTag { get; set; }
public string outboundTag { get; set; } public string? outboundTag { get; set; }
public List<string> ip { get; set; } public string? balancerTag { get; set; }
public List<string> domain { get; set; } public List<string>? ip { get; set; }
public List<string> protocol { get; set; } public List<string>? domain { get; set; }
public List<string>? protocol { get; set; }
}
public class BalancersItem4Ray
{
public List<string>? selector { get; set; }
public BalancersStrategy4Ray? strategy { get; set; }
public string? tag { get; set; }
}
public class BalancersStrategy4Ray
{
public string? type { get; set; }
} }
public class StreamSettings4Ray public class StreamSettings4Ray
@@ -415,42 +439,57 @@ namespace v2rayN.Mode
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public TlsSettings4Ray tlsSettings { get; set; } public TlsSettings4Ray? tlsSettings { get; set; }
/// <summary> /// <summary>
/// Tcp传输额外设置 /// Tcp传输额外设置
/// </summary> /// </summary>
public TcpSettings4Ray tcpSettings { get; set; } public TcpSettings4Ray? tcpSettings { get; set; }
/// <summary> /// <summary>
/// Kcp传输额外设置 /// Kcp传输额外设置
/// </summary> /// </summary>
public KcpSettings4Ray kcpSettings { get; set; } public KcpSettings4Ray? kcpSettings { get; set; }
/// <summary> /// <summary>
/// ws传输额外设置 /// ws传输额外设置
/// </summary> /// </summary>
public WsSettings4Ray wsSettings { get; set; } public WsSettings4Ray? wsSettings { get; set; }
/// <summary>
///
/// </summary>
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
/// <summary>
///
/// </summary>
public SplithttpSettings4Ray? splithttpSettings { get; set; }
/// <summary> /// <summary>
/// h2传输额外设置 /// h2传输额外设置
/// </summary> /// </summary>
public HttpSettings4Ray httpSettings { get; set; } public HttpSettings4Ray? httpSettings { get; set; }
/// <summary> /// <summary>
/// QUIC /// QUIC
/// </summary> /// </summary>
public QuicSettings4Ray quicSettings { get; set; } public QuicSettings4Ray? quicSettings { get; set; }
/// <summary> /// <summary>
/// VLESS only /// VLESS only
/// </summary> /// </summary>
public TlsSettings4Ray realitySettings { get; set; } public TlsSettings4Ray? realitySettings { get; set; }
/// <summary> /// <summary>
/// grpc /// grpc
/// </summary> /// </summary>
public GrpcSettings4Ray grpcSettings { get; set; } public GrpcSettings4Ray? grpcSettings { get; set; }
/// <summary>
/// sockopt
/// </summary>
public Sockopt4Ray? sockopt { get; set; }
} }
public class TlsSettings4Ray public class TlsSettings4Ray
@@ -472,7 +511,7 @@ namespace v2rayN.Mode
public string? fingerprint { get; set; } public string? fingerprint { get; set; }
public bool? show { get; set; } = false; public bool? show { get; set; }
public string? publicKey { get; set; } public string? publicKey { get; set; }
public string? shortId { get; set; } public string? shortId { get; set; }
public string? spiderX { get; set; } public string? spiderX { get; set; }
@@ -575,10 +614,34 @@ namespace v2rayN.Mode
/// <summary> /// <summary>
/// 用户代理 /// 用户代理
/// </summary> /// </summary>
[JsonProperty("User-Agent")] [JsonPropertyName("User-Agent")]
public string UserAgent { get; set; } public string UserAgent { get; set; }
} }
public class HttpupgradeSettings4Ray
{
/// <summary>
///
/// </summary>
public string? path { get; set; }
/// <summary>
///
/// </summary>
public string? host { get; set; }
}
public class SplithttpSettings4Ray
{
public string? path { get; set; }
public string? host { get; set; }
public int? maxUploadSize { get; set; }
public int? maxConcurrentUploads { get; set; }
}
public class HttpSettings4Ray public class HttpSettings4Ray
{ {
/// <summary> /// <summary>
@@ -612,7 +675,8 @@ namespace v2rayN.Mode
public class GrpcSettings4Ray public class GrpcSettings4Ray
{ {
public string serviceName { get; set; } public string? authority { get; set; }
public string? serviceName { get; set; }
public bool multiMode { get; set; } public bool multiMode { get; set; }
public int idle_timeout { get; set; } public int idle_timeout { get; set; }
public int health_check_timeout { get; set; } public int health_check_timeout { get; set; }
@@ -632,4 +696,16 @@ namespace v2rayN.Mode
/// </summary> /// </summary>
public string pass { get; set; } public string pass { get; set; }
} }
public class Sockopt4Ray
{
public string? dialerProxy { get; set; }
}
public class FragmentItem4Ray
{
public string? packets { get; set; }
public string? length { get; set; }
public string? interval { get; set; }
}
} }

View File

@@ -1,4 +1,4 @@
namespace v2rayN.Mode namespace ServiceLib.Models
{ {
/// <summary> /// <summary>
/// Tcp伪装http的Request只要Host /// Tcp伪装http的Request只要Host

View File

@@ -0,0 +1,44 @@
using System.Text.Json.Serialization;
namespace ServiceLib.Models
{
/// <summary>
/// https://github.com/2dust/v2rayN/wiki/
/// </summary>
[Serializable]
public class VmessQRCode
{
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public int v { get; set; } = 2;
public string ps { get; set; } = string.Empty;
public string add { get; set; } = string.Empty;
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public int port { get; set; } = 0;
public string id { get; set; } = string.Empty;
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public int aid { get; set; } = 0;
public string scy { get; set; } = string.Empty;
public string net { get; set; } = string.Empty;
public string type { get; set; } = string.Empty;
public string host { get; set; } = string.Empty;
public string path { get; set; } = string.Empty;
public string tls { get; set; } = string.Empty;
public string sni { get; set; } = string.Empty;
public string alpn { get; set; } = string.Empty;
public string fp { get; set; } = string.Empty;
}
}

View File

@@ -117,9 +117,6 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>صادرات دسته ای محتوای اشتراک به کلیپ بورد با موفقیت انجام شد</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve"> <data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>Batch export share URL to clipboard successfully</value> <value>Batch export share URL to clipboard successfully</value>
</data> </data>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve"> <data name="FillCorrectServerPort" xml:space="preserve">
<value>لطفا فرمت صحیح پورت سرور را پر کنید</value> <value>لطفا فرمت صحیح پورت سرور را پر کنید</value>
</data> </data>
<data name="FillKcpParameters" xml:space="preserve">
<value>لطفاً پارامترهای KCP را به درستی پر کنید</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve"> <data name="FillLocalListeningPort" xml:space="preserve">
<value>لطفاً پورت گوش دادن محلی را پر کنید</value> <value>لطفاً پورت گوش دادن محلی را پر کنید</value>
</data> </data>
@@ -174,15 +168,9 @@
<data name="FillUUID" xml:space="preserve"> <data name="FillUUID" xml:space="preserve">
<value>لطفا شناسه کاربری را وارد کنید</value> <value>لطفا شناسه کاربری را وارد کنید</value>
</data> </data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>فایل پیکربندی مشتری صحیح نیست، لطفا بررسی کنید</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve"> <data name="Incorrectconfiguration" xml:space="preserve">
<value>پیکربندی درستی نیست، لطفا بررسی کنید</value> <value>پیکربندی درستی نیست، لطفا بررسی کنید</value>
</data> </data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value>فایل پیکربندی سرور صحیح نیست، لطفا بررسی کنید</value>
</data>
<data name="InitialConfiguration" xml:space="preserve"> <data name="InitialConfiguration" xml:space="preserve">
<value>پیکربندی اولیه</value> <value>پیکربندی اولیه</value>
</data> </data>
@@ -267,9 +255,6 @@
<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>
<data name="NonVmessService" xml:space="preserve">
<value> non-standard service, this feature is invalid</value>
</data>
<data name="NotFoundCore" xml:space="preserve"> <data name="NotFoundCore" xml:space="preserve">
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value> <value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
</data> </data>
@@ -415,15 +400,9 @@
<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>
</data> </data>
<data name="SystemProxy" xml:space="preserve">
<value>پروکسی سیستم</value>
</data>
<data name="Speedtesting" xml:space="preserve"> <data name="Speedtesting" xml:space="preserve">
<value>درحال تست کردن...</value> <value>درحال تست کردن...</value>
</data> </data>
<data name="TooManyServersTip" xml:space="preserve">
<value>تعداد سرورها خیلی زیاد است، لطفا رابط اصلی را باز کنید</value>
</data>
<data name="LabLAN" xml:space="preserve"> <data name="LabLAN" xml:space="preserve">
<value>LAN</value> <value>LAN</value>
</data> </data>
@@ -529,9 +508,6 @@
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>تمام آمار خدمات را پاک کنید</value> <value>تمام آمار خدمات را پاک کنید</value>
</data> </data>
<data name="menuPingServer" xml:space="preserve">
<value>تست پینگ سرورها (Ctrl+P)</value>
</data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>آزمایش سرورها با تاخیر واقعی (Ctrl+R)</value> <value>آزمایش سرورها با تاخیر واقعی (Ctrl+R)</value>
</data> </data>
@@ -544,18 +520,12 @@
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>تست سرورها با tcping (Ctrl+O)</value> <value>تست سرورها با tcping (Ctrl+O)</value>
</data> </data>
<data name="menuTestMe" xml:space="preserve">
<value>وضعیت سرویس فعلی را تست کنید</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value> <value>سرور انتخابی را برای پیکربندی کلاینت صادر کنید</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value> <value>URL های اشتراک گذاری را به کلیپ بورد صادر کنید (Ctrl+C)</value>
</data> </data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>اشتراک (base64) را به کلیپ بورد صادر کنید</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>یک سرور پیکربندی سفارشی اضافه شود</value> <value>یک سرور پیکربندی سفارشی اضافه شود</value>
</data> </data>
@@ -586,9 +556,6 @@
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>کپی همه</value> <value>کپی همه</value>
</data> </data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>فیلترهای پیام را تنظیم کنید</value>
</data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>انتخاب همه (Ctrl+A)</value> <value>انتخاب همه (Ctrl+A)</value>
</data> </data>
@@ -701,7 +668,7 @@
<value>txtPreSocksPort</value> <value>txtPreSocksPort</value>
</data> </data>
<data name="TipPreSocksPort" xml:space="preserve"> <data name="TipPreSocksPort" xml:space="preserve">
<value>* After setting this value, an socks service will be started using sing-box to provide functions such as speed display</value> <value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</value>
</data> </data>
<data name="TbBrowse" xml:space="preserve"> <data name="TbBrowse" xml:space="preserve">
<value>Browse</value> <value>Browse</value>
@@ -958,6 +925,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve"> <data name="TbSettingsRouteOnly" xml:space="preserve">
<value>فقط مسیر</value> <value>فقط مسیر</value>
</data> </data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>يەرلىك (Intranet) ئادرېسلارغا ۋاكالەتچى مۇلازىمېتىر ئىشلەتمەڭ</value>
</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 test Latency and speed (Ctrl+E)</value>
</data> </data>
@@ -988,15 +958,6 @@
<data name="TbSettingsTunMode" xml:space="preserve"> <data name="TbSettingsTunMode" xml:space="preserve">
<value>تنظیمات TunMode</value> <value>تنظیمات TunMode</value>
</data> </data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>Direct IP CIDR, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>Direct Process name, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>نمایش کنسول</value>
</data>
<data name="TbSettingsDefUserAgent" xml:space="preserve"> <data name="TbSettingsDefUserAgent" xml:space="preserve">
<value>User-Agent</value> <value>User-Agent</value>
</data> </data>
@@ -1006,4 +967,70 @@
<data name="TbSettingsEnableHWA" xml:space="preserve"> <data name="TbSettingsEnableHWA" xml:space="preserve">
<value>فعال‌سازی شتاب‌دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد)</value> <value>فعال‌سازی شتاب‌دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>مرتب سازی</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>تاخیر</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>سرعت دانلود</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>ترافیک دانلود</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>نام</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>زمان</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>سرعت اپلود</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>ترافیک آپلود</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>اتصالات</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>بستن اتصال</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>تمام اتصالات را ببندید</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>پروکسی</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>نوع قانون</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>Direct</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>Global</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>تغییر نده</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>قانون</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>Part Node Latency Test</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
</root> </root>

View File

@@ -117,11 +117,8 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>Batch export subscription to clipboard successfully</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve"> <data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>Batch export share URL to clipboard successfully</value> <value>Export Share Link to Clipboard Successfully</value>
</data> </data>
<data name="CheckServerSettings" xml:space="preserve"> <data name="CheckServerSettings" xml:space="preserve">
<value>Please check the server settings first</value> <value>Please check the server settings first</value>
@@ -148,7 +145,7 @@
<value>Failed to generate default configuration file</value> <value>Failed to generate default configuration file</value>
</data> </data>
<data name="FailedGetDefaultConfiguration" xml:space="preserve"> <data name="FailedGetDefaultConfiguration" xml:space="preserve">
<value> Failed to get the default configuration</value> <value>Failed to get the default configuration</value>
</data> </data>
<data name="FailedImportedCustomServer" xml:space="preserve"> <data name="FailedImportedCustomServer" xml:space="preserve">
<value>Failed to import custom configuration server</value> <value>Failed to import custom configuration server</value>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve"> <data name="FillCorrectServerPort" xml:space="preserve">
<value>Please fill in the correct format server port</value> <value>Please fill in the correct format server port</value>
</data> </data>
<data name="FillKcpParameters" xml:space="preserve">
<value>Please fill in the KCP parameters correctly</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve"> <data name="FillLocalListeningPort" xml:space="preserve">
<value>Please fill in the local listening port</value> <value>Please fill in the local listening port</value>
</data> </data>
@@ -174,14 +168,8 @@
<data name="FillUUID" xml:space="preserve"> <data name="FillUUID" xml:space="preserve">
<value>Please fill in the user ID</value> <value>Please fill in the user ID</value>
</data> </data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value> is not the correct client configuration file, please check</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve"> <data name="Incorrectconfiguration" xml:space="preserve">
<value> is not the correct configuration, please check</value> <value>Is not the correct configuration, please check</value>
</data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value> is not the correct server configuration file, please check</value>
</data> </data>
<data name="InitialConfiguration" xml:space="preserve"> <data name="InitialConfiguration" xml:space="preserve">
<value>Initial Configuration</value> <value>Initial Configuration</value>
@@ -250,13 +238,13 @@
<value>Invalid subscription content</value> <value>Invalid subscription content</value>
</data> </data>
<data name="MsgUnpacking" xml:space="preserve"> <data name="MsgUnpacking" xml:space="preserve">
<value>is unpacking...</value> <value>Is unpacking......</value>
</data> </data>
<data name="MsgUpdateSubscriptionEnd" xml:space="preserve"> <data name="MsgUpdateSubscriptionEnd" xml:space="preserve">
<value>Update subscription end</value> <value>Update subscriptions end</value>
</data> </data>
<data name="MsgUpdateSubscriptionStart" xml:space="preserve"> <data name="MsgUpdateSubscriptionStart" xml:space="preserve">
<value>Update subscription starts</value> <value>Update subscriptions start</value>
</data> </data>
<data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgUpdateV2rayCoreSuccessfully" xml:space="preserve">
<value>Update Core successfully</value> <value>Update Core successfully</value>
@@ -267,9 +255,6 @@
<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>
<data name="NonVmessService" xml:space="preserve">
<value> non-standard service, this feature is invalid</value>
</data>
<data name="NotFoundCore" xml:space="preserve"> <data name="NotFoundCore" xml:space="preserve">
<value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value> <value>The Core file (file name: {1}) was not found under the folder ({0}), please download and put it in the folder, download address: {2}</value>
</data> </data>
@@ -277,7 +262,7 @@
<value>Scan completed, no valid QR code found</value> <value>Scan completed, no valid QR code found</value>
</data> </data>
<data name="OperationFailed" xml:space="preserve"> <data name="OperationFailed" xml:space="preserve">
<value> operation failed, please check and retry</value> <value>Operation failed, please check and retry</value>
</data> </data>
<data name="PleaseFillRemarks" xml:space="preserve"> <data name="PleaseFillRemarks" xml:space="preserve">
<value>Please Fill Remarks</value> <value>Please Fill Remarks</value>
@@ -308,13 +293,13 @@
{0}</value> {0}</value>
</data> </data>
<data name="SuccessfullyImportedCustomServer" xml:space="preserve"> <data name="SuccessfullyImportedCustomServer" xml:space="preserve">
<value>Custom configuration server imported successfully.</value> <value>Custom configuration server imported successfully</value>
</data> </data>
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve"> <data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
<value>{0} servers have been imported from clipboard.</value> <value>{0} servers have been imported from clipboard</value>
</data> </data>
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve"> <data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
<value>Scan import URL successfully</value> <value>Scan import the shared link successfully</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>The ping of current service: {0} ms</value> <value>The ping of current service: {0} ms</value>
@@ -335,13 +320,13 @@
<value>Remarks</value> <value>Remarks</value>
</data> </data>
<data name="LvUrl" xml:space="preserve"> <data name="LvUrl" xml:space="preserve">
<value>Url(Optional)</value> <value>URL(Optional)</value>
</data> </data>
<data name="LvCount" xml:space="preserve"> <data name="LvCount" xml:space="preserve">
<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 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>
@@ -359,13 +344,13 @@
<value>Please fill in the correct custom DNS</value> <value>Please fill in the correct custom DNS</value>
</data> </data>
<data name="TransportPathTip1" xml:space="preserve"> <data name="TransportPathTip1" xml:space="preserve">
<value>*ws path</value> <value>*ws/httpupgrade/splithttp path</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>*h2 path</value>
</data> </data>
<data name="TransportPathTip3" xml:space="preserve"> <data name="TransportPathTip3" xml:space="preserve">
<value>*QUIC key/Kcp seed</value> <value>*QUIC key/KCP seed</value>
</data> </data>
<data name="TransportPathTip4" xml:space="preserve"> <data name="TransportPathTip4" xml:space="preserve">
<value>*grpc serviceName</value> <value>*grpc serviceName</value>
@@ -374,7 +359,7 @@
<value>*http host Separated by commas (,)</value> <value>*http host Separated by commas (,)</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws host</value> <value>*ws/httpupgrade/splithttp host</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host Separated by commas (,)</value> <value>*h2 host Separated by commas (,)</value>
@@ -398,7 +383,7 @@
<value>TLS</value> <value>TLS</value>
</data> </data>
<data name="TransportPathTip5" xml:space="preserve"> <data name="TransportPathTip5" xml:space="preserve">
<value>*Kcp seed</value> <value>*kcp seed</value>
</data> </data>
<data name="RegisterGlobalHotkeyFailed" xml:space="preserve"> <data name="RegisterGlobalHotkeyFailed" xml:space="preserve">
<value>Global hotkey {0} registered failed, reason {1}</value> <value>Global hotkey {0} registered failed, reason {1}</value>
@@ -415,15 +400,9 @@
<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>
</data> </data>
<data name="SystemProxy" xml:space="preserve">
<value>System proxy</value>
</data>
<data name="Speedtesting" xml:space="preserve"> <data name="Speedtesting" xml:space="preserve">
<value>Testing...</value> <value>Testing...</value>
</data> </data>
<data name="TooManyServersTip" xml:space="preserve">
<value>Too many servers, please open the main interface</value>
</data>
<data name="LabLAN" xml:space="preserve"> <data name="LabLAN" xml:space="preserve">
<value>LAN</value> <value>LAN</value>
</data> </data>
@@ -443,13 +422,13 @@
<value>Exit</value> <value>Exit</value>
</data> </data>
<data name="menuGlobalHotkeySetting" xml:space="preserve"> <data name="menuGlobalHotkeySetting" xml:space="preserve">
<value>GlobalHotkeySetting</value> <value>Global Hotkey Setting</value>
</data> </data>
<data name="menuHelp" xml:space="preserve"> <data name="menuHelp" xml:space="preserve">
<value>Help</value> <value>Help</value>
</data> </data>
<data name="menuOptionSetting" xml:space="preserve"> <data name="menuOptionSetting" xml:space="preserve">
<value>OptionSetting</value> <value>Option Setting</value>
</data> </data>
<data name="menuPromotion" xml:space="preserve"> <data name="menuPromotion" xml:space="preserve">
<value>Promotion</value> <value>Promotion</value>
@@ -458,7 +437,7 @@
<value>Reload</value> <value>Reload</value>
</data> </data>
<data name="menuRoutingSetting" xml:space="preserve"> <data name="menuRoutingSetting" xml:space="preserve">
<value>RoutingSetting</value> <value>Routing Setting</value>
</data> </data>
<data name="menuServers" xml:space="preserve"> <data name="menuServers" xml:space="preserve">
<value>Servers</value> <value>Servers</value>
@@ -473,16 +452,16 @@
<value>Update current subscription with proxy</value> <value>Update current subscription with proxy</value>
</data> </data>
<data name="menuSubscription" xml:space="preserve"> <data name="menuSubscription" xml:space="preserve">
<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 Settings</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 subscriptions without proxy</value>
</data> </data>
<data name="menuSubUpdateViaProxy" xml:space="preserve"> <data name="menuSubUpdateViaProxy" xml:space="preserve">
<value>Update subscription with proxy</value> <value>Update subscriptions with proxy</value>
</data> </data>
<data name="menuSystemproxy" xml:space="preserve"> <data name="menuSystemproxy" xml:space="preserve">
<value>System proxy</value> <value>System proxy</value>
@@ -494,7 +473,7 @@
<value>Do not change system proxy</value> <value>Do not change system proxy</value>
</data> </data>
<data name="menuSystemProxyPac" xml:space="preserve"> <data name="menuSystemProxyPac" xml:space="preserve">
<value>Pac Mode</value> <value>PAC mode</value>
</data> </data>
<data name="menuSystemProxySet" xml:space="preserve"> <data name="menuSystemProxySet" xml:space="preserve">
<value>Set system proxy</value> <value>Set system proxy</value>
@@ -509,10 +488,10 @@
<value>Follow System Theme</value> <value>Follow System Theme</value>
</data> </data>
<data name="TbSettingsLanguage" xml:space="preserve"> <data name="TbSettingsLanguage" xml:space="preserve">
<value>Language(Restart)</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>Importing Share Links from clipboard (Ctrl+V)</value>
</data> </data>
<data name="menuAddServerViaScan" xml:space="preserve"> <data name="menuAddServerViaScan" xml:space="preserve">
<value>Scan QR code on the screen (Ctrl+S)</value> <value>Scan QR code on the screen (Ctrl+S)</value>
@@ -532,9 +511,6 @@
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>Clear all service statistics</value> <value>Clear all service statistics</value>
</data> </data>
<data name="menuPingServer" xml:space="preserve">
<value>Test servers ping (Ctrl+P)</value>
</data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>Test servers real delay (Ctrl+R)</value> <value>Test servers real delay (Ctrl+R)</value>
</data> </data>
@@ -547,17 +523,11 @@
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>Test servers with tcping (Ctrl+O)</value> <value>Test servers with tcping (Ctrl+O)</value>
</data> </data>
<data name="menuTestMe" xml:space="preserve">
<value>Test current service status</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>Export selected server for client configuration</value> <value>Export selected server for complete configuration</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>Export share URLs to clipboard (Ctrl+C)</value> <value>Export Share Link to Clipboard (Ctrl+C)</value>
</data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>Export subscription (base64) share to clipboard</value>
</data> </data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>Add a custom configuration server</value> <value>Add a custom configuration server</value>
@@ -578,22 +548,19 @@
<value>Add [VMess] server</value> <value>Add [VMess] server</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>Select All (Ctrl+A)</value> <value>Select all (Ctrl+A)</value>
</data> </data>
<data name="menuMsgViewClear" xml:space="preserve"> <data name="menuMsgViewClear" xml:space="preserve">
<value>Clear All</value> <value>Clear all</value>
</data> </data>
<data name="menuMsgViewCopy" xml:space="preserve"> <data name="menuMsgViewCopy" xml:space="preserve">
<value>Copy (Ctrl+C)</value> <value>Copy (Ctrl+C)</value>
</data> </data>
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Copy All</value> <value>Copy all</value>
</data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>Set message filters</value>
</data> </data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Select All (Ctrl+A)</value> <value>Select all (Ctrl+A)</value>
</data> </data>
<data name="menuSubAdd" xml:space="preserve"> <data name="menuSubAdd" xml:space="preserve">
<value>Add</value> <value>Add</value>
@@ -608,7 +575,7 @@
<value>Share</value> <value>Share</value>
</data> </data>
<data name="LvEnabled" xml:space="preserve"> <data name="LvEnabled" xml:space="preserve">
<value>Enabled Update</value> <value>Enable update</value>
</data> </data>
<data name="LvSort" xml:space="preserve"> <data name="LvSort" xml:space="preserve">
<value>Sort</value> <value>Sort</value>
@@ -632,10 +599,10 @@
<value>AllowInsecure</value> <value>AllowInsecure</value>
</data> </data>
<data name="TbAlpn" xml:space="preserve"> <data name="TbAlpn" xml:space="preserve">
<value>Alpn</value> <value>ALPN</value>
</data> </data>
<data name="TbAlterId" xml:space="preserve"> <data name="TbAlterId" xml:space="preserve">
<value>AlterId</value> <value>AlterID</value>
</data> </data>
<data name="TbFingerprint" xml:space="preserve"> <data name="TbFingerprint" xml:space="preserve">
<value>Fingerprint</value> <value>Fingerprint</value>
@@ -701,10 +668,10 @@
<value>Encryption</value> <value>Encryption</value>
</data> </data>
<data name="TbPreSocksPort" xml:space="preserve"> <data name="TbPreSocksPort" xml:space="preserve">
<value>txtPreSocksPort</value> <value>Socks port</value>
</data> </data>
<data name="TipPreSocksPort" xml:space="preserve"> <data name="TipPreSocksPort" xml:space="preserve">
<value>* After setting this value, an socks service will be started using sing-box to provide functions such as speed display</value> <value>* After setting this value, an socks service will be started using Xray/sing-box(Tun) to provide functions such as speed display</value>
</data> </data>
<data name="TbBrowse" xml:space="preserve"> <data name="TbBrowse" xml:space="preserve">
<value>Browse</value> <value>Browse</value>
@@ -755,7 +722,7 @@
<value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value> <value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve"> <data name="TbSettingsHttpPort" xml:space="preserve">
<value>Http Port</value> <value>HTTP Port</value>
</data> </data>
<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>
@@ -788,7 +755,7 @@
<value>Turn on Sniffing</value> <value>Turn on Sniffing</value>
</data> </data>
<data name="TbSettingsSocksPort" xml:space="preserve"> <data name="TbSettingsSocksPort" xml:space="preserve">
<value>Socks Port</value> <value>SOCKS Port</value>
</data> </data>
<data name="TbSettingsStartBoot" xml:space="preserve"> <data name="TbSettingsStartBoot" xml:space="preserve">
<value>Start on boot</value> <value>Start on boot</value>
@@ -797,7 +764,7 @@
<value>Enable Statistics (Require restart)</value> <value>Enable Statistics (Require restart)</value>
</data> </data>
<data name="TbSettingsSubConvert" xml:space="preserve"> <data name="TbSettingsSubConvert" xml:space="preserve">
<value>Subscription conversion Url</value> <value>Subscription conversion URL</value>
</data> </data>
<data name="TbSettingsSystemproxy" xml:space="preserve"> <data name="TbSettingsSystemproxy" xml:space="preserve">
<value>System proxy settings</value> <value>System proxy settings</value>
@@ -821,10 +788,10 @@
<value>Display GUI</value> <value>Display GUI</value>
</data> </data>
<data name="TbGlobalHotkeySetting" xml:space="preserve"> <data name="TbGlobalHotkeySetting" xml:space="preserve">
<value>GlobalHotkey Settings</value> <value>Global Hotkey 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>
</data> </data>
<data name="TbNotChangeSystemProxy" xml:space="preserve"> <data name="TbNotChangeSystemProxy" xml:space="preserve">
<value>Do not change system proxy</value> <value>Do not change system proxy</value>
@@ -836,7 +803,7 @@
<value>Set system proxy</value> <value>Set system proxy</value>
</data> </data>
<data name="TbSystemProxyPac" xml:space="preserve"> <data name="TbSystemProxyPac" xml:space="preserve">
<value>Pac Mode</value> <value>PAC mode</value>
</data> </data>
<data name="menuShareServer" xml:space="preserve"> <data name="menuShareServer" xml:space="preserve">
<value>Share Server (Ctrl+F)</value> <value>Share Server (Ctrl+F)</value>
@@ -845,10 +812,10 @@
<value>Routing</value> <value>Routing</value>
</data> </data>
<data name="NotRunAsAdmin" xml:space="preserve"> <data name="NotRunAsAdmin" xml:space="preserve">
<value>Not Run As Admin</value> <value>Not run as Admin</value>
</data> </data>
<data name="RunAsAdmin" xml:space="preserve"> <data name="RunAsAdmin" xml:space="preserve">
<value>Run As Admin</value> <value>Run as Admin</value>
</data> </data>
<data name="menuMoveBottom" xml:space="preserve"> <data name="menuMoveBottom" xml:space="preserve">
<value>Move to bottom (B)</value> <value>Move to bottom (B)</value>
@@ -920,13 +887,13 @@
<value>Import Rules From File</value> <value>Import Rules From File</value>
</data> </data>
<data name="menuImportRulesFromUrl" xml:space="preserve"> <data name="menuImportRulesFromUrl" xml:space="preserve">
<value>Import Rules From Sub Url</value> <value>Import Rules From Subscription URL</value>
</data> </data>
<data name="menuRoutingRuleSetting" xml:space="preserve"> <data name="menuRoutingRuleSetting" xml:space="preserve">
<value>Rule Settings</value> <value>Rule Settings</value>
</data> </data>
<data name="menuRuleAdd" xml:space="preserve"> <data name="menuRuleAdd" xml:space="preserve">
<value>Rule Add</value> <value>Add Rule</value>
</data> </data>
<data name="menuRuleExportSelected" xml:space="preserve"> <data name="menuRuleExportSelected" xml:space="preserve">
<value>Export Selected Rules</value> <value>Export Selected Rules</value>
@@ -935,7 +902,7 @@
<value>Rule List</value> <value>Rule List</value>
</data> </data>
<data name="menuRuleRemove" xml:space="preserve"> <data name="menuRuleRemove" xml:space="preserve">
<value>Remove Rules (Delete)</value> <value>Remove Rule (Delete)</value>
</data> </data>
<data name="menuRoutingRuleDetailsSetting" xml:space="preserve"> <data name="menuRoutingRuleDetailsSetting" xml:space="preserve">
<value>RoutingRuleDetailsSetting</value> <value>RoutingRuleDetailsSetting</value>
@@ -950,7 +917,7 @@
<value>Support DnsObject, Click to view the document</value> <value>Support DnsObject, Click to view the document</value>
</data> </data>
<data name="SubUrlTips" xml:space="preserve"> <data name="SubUrlTips" xml:space="preserve">
<value>Group please leave blank here</value> <value>For group please leave blank here</value>
</data> </data>
<data name="TipChangeRouting" xml:space="preserve"> <data name="TipChangeRouting" xml:space="preserve">
<value>Routing setting is changed</value> <value>Routing setting is changed</value>
@@ -961,6 +928,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve"> <data name="TbSettingsRouteOnly" xml:space="preserve">
<value>RouteOnly</value> <value>RouteOnly</value>
</data> </data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>Do not use proxy servers for local (intranet) addresses</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>One-click multi test Latency and speed (Ctrl+E)</value> <value>One-click multi test Latency and speed (Ctrl+E)</value>
</data> </data>
@@ -980,7 +950,7 @@
<value>Display Log</value> <value>Display Log</value>
</data> </data>
<data name="menuImportOldGuiConfig" xml:space="preserve"> <data name="menuImportOldGuiConfig" xml:space="preserve">
<value>Import old config guiNConfig</value> <value>Import old config (guiNConfig)</value>
</data> </data>
<data name="TbEnableTunAs" xml:space="preserve"> <data name="TbEnableTunAs" xml:space="preserve">
<value>Enable Tun</value> <value>Enable Tun</value>
@@ -991,21 +961,9 @@
<data name="TbSettingsTunMode" xml:space="preserve"> <data name="TbSettingsTunMode" xml:space="preserve">
<value>TunMode settings</value> <value>TunMode settings</value>
</data> </data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>Direct IP CIDR, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>Direct Process name, separated by commas (,)</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>Show console</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve"> <data name="menuMoveToGroup" xml:space="preserve">
<value>Move to group</value> <value>Move to group</value>
</data> </data>
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
<value>Custom Template</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve"> <data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Enable Server Drag Drop Sort(Require restart)</value> <value>Enable Server Drag Drop Sort(Require restart)</value>
</data> </data>
@@ -1040,31 +998,19 @@
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value> <value>Copy the font TTF/TTC 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 = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
</data> </data>
<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"> <data name="TbSettingsFontSize" xml:space="preserve">
<value>FontSize</value> <value>Font Size</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>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve"> <data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>SpeedTest Single Timeout Value</value> <value>SpeedTest Single Timeout Value</value>
</data> </data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest Url</value> <value>SpeedTest URL</value>
</data>
<data name="TbSettingsTunModeDNS" xml:space="preserve">
<value>DNS object, e.g. {"servers":[]}</value>
</data> </data>
<data name="menuMoveTo" xml:space="preserve"> <data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</value> <value>Move up and down</value>
@@ -1082,7 +1028,7 @@
<value>Enable hardware acceleration(Require restart)</value> <value>Enable hardware acceleration(Require restart)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing</value> <value>Waiting for testing (press ESC to terminate)...</value>
</data> </data>
<data name="TipDisplayLog" xml:space="preserve"> <data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value> <value>Please turn off when there is an abnormal disconnection</value>
@@ -1091,16 +1037,16 @@
<value>Updates are not enabled, skip this subscription</value> <value>Updates are not enabled, skip this subscription</value>
</data> </data>
<data name="menuRebootAsAdmin" xml:space="preserve"> <data name="menuRebootAsAdmin" xml:space="preserve">
<value>Reboot as administrator</value> <value>Restart as Administrator</value>
</data> </data>
<data name="LvMoreUrl" xml:space="preserve"> <data name="LvMoreUrl" xml:space="preserve">
<value>More urls, separated by commas;Subscription conversion will be invalid</value> <value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data> </data>
<data name="SpeedDisplayText" xml:space="preserve"> <data name="SpeedDisplayText" xml:space="preserve">
<value>{0}:{1}/s↑ | {2}/s↓</value> <value>{0} : {1}/s↑ | {2}/s↓</value>
</data> </data>
<data name="LvAutoUpdateInterval" xml:space="preserve"> <data name="LvAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval(minutes)</value> <value>Automatic update interval (minutes)</value>
</data> </data>
<data name="TbSettingsLogEnabledToFile" xml:space="preserve"> <data name="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>Enable logging to file</value> <value>Enable logging to file</value>
@@ -1139,7 +1085,7 @@
<value>Domain</value> <value>Domain</value>
</data> </data>
<data name="menuAddHysteria2Server" xml:space="preserve"> <data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Trojan] server</value> <value>Add [Hysteria2] server</value>
</data> </data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve"> <data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Dw)</value> <value>Hysteria Max bandwidth (Up/Dw)</value>
@@ -1147,4 +1093,190 @@
<data name="TbSettingsUseSystemHosts" xml:space="preserve"> <data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>Use System Hosts</value> <value>Use System Hosts</value>
</data> </data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>Add [Tuic] server</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="LvPrevProfileTip" xml:space="preserve">
<value>Please make sure the remarks exists and is unique</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Enable additional Inbound</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [Wireguard] server</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>obfs password</value>
</data>
<data name="TbRuleMatchingTips" xml:space="preserve">
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value>
</data>
<data name="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>Updating subscription, only determine remarks exists</value>
</data>
<data name="SpeedtestingStop" xml:space="preserve">
<value>Test terminating...</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [Http] server</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value>
</data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>Enable cache file for sing-box (ruleset files)</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>Sorting</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>Delay</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>Download Speed</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>Download Traffic</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>Host</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>Name</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>Network</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>Time</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>Type</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>Upload Speed</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>Upload Traffic</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>Connections</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>Close Connection</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>Close All Connection</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>Proxies</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>Rule mode</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>Direct</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>Global</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>Do not change</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>Rule</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>Part Node Latency Test</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>Refresh Proxies</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Default domain strategy for outbound</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>Multi-Server lowest latency</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>Main layout orientation(Require restart)</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>Multi-server load balancing</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound DNS address</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>Auto column width adjustment</value>
</data>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>Export Base64-encoded Share Links to Clipboard</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected server for complete configuration to clipboard</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</value>
</data>
</root> </root>

View File

@@ -117,9 +117,6 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="BatchExportSubscriptionSuccessfully" xml:space="preserve">
<value>Экспортирование подписок в буфер обмена успешно завершено</value>
</data>
<data name="BatchExportURLSuccessfully" xml:space="preserve"> <data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>Экспортирование URL в буфер обмена успешно завершено</value> <value>Экспортирование URL в буфер обмена успешно завершено</value>
</data> </data>
@@ -159,9 +156,6 @@
<data name="FillCorrectServerPort" xml:space="preserve"> <data name="FillCorrectServerPort" xml:space="preserve">
<value>Пожалуйста, укажите порт сервера в правильном формате</value> <value>Пожалуйста, укажите порт сервера в правильном формате</value>
</data> </data>
<data name="FillKcpParameters" xml:space="preserve">
<value>Пожалуйста, заполните параметры KCP корректно</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve"> <data name="FillLocalListeningPort" xml:space="preserve">
<value>Пожалуйста, укажите локальный порт прослушивания</value> <value>Пожалуйста, укажите локальный порт прослушивания</value>
</data> </data>
@@ -174,15 +168,9 @@
<data name="FillUUID" xml:space="preserve"> <data name="FillUUID" xml:space="preserve">
<value>Пожалуйста, заполните идентификатор пользователя</value> <value>Пожалуйста, заполните идентификатор пользователя</value>
</data> </data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>Некорректный файл конфигурации клиента, пожалуйста, проверьте</value>
</data>
<data name="Incorrectconfiguration" xml:space="preserve"> <data name="Incorrectconfiguration" xml:space="preserve">
<value>Некорректная конфигурация, пожалуйста, проверьте</value> <value>Некорректная конфигурация, пожалуйста, проверьте</value>
</data> </data>
<data name="IncorrectServerConfiguration" xml:space="preserve">
<value>Некорректный файл конфигурации сервера, пожалуйста, проверьте</value>
</data>
<data name="InitialConfiguration" xml:space="preserve"> <data name="InitialConfiguration" xml:space="preserve">
<value>Исходная конфигурация</value> <value>Исходная конфигурация</value>
</data> </data>
@@ -267,9 +255,6 @@
<data name="NonvmessOrssProtocol" xml:space="preserve"> <data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Не является протоколом Vmess или SS</value> <value>Не является протоколом Vmess или SS</value>
</data> </data>
<data name="NonVmessService" xml:space="preserve">
<value> нестандартный сервис, эта функция недействительна</value>
</data>
<data name="NotFoundCore" xml:space="preserve"> <data name="NotFoundCore" xml:space="preserve">
<value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value> <value>Файл Core (имя файла: {1}) не найден в папке ({0}), загрузите и поместите его в папку, адрес загрузки: {2}</value>
</data> </data>
@@ -415,15 +400,9 @@
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера</value> <value>Пожалуйста, просмотрите, чтобы импортировать конфигурацию сервера</value>
</data> </data>
<data name="SystemProxy" xml:space="preserve">
<value>Системный прокси</value>
</data>
<data name="Speedtesting" xml:space="preserve"> <data name="Speedtesting" xml:space="preserve">
<value>Тестирование...</value> <value>Тестирование...</value>
</data> </data>
<data name="TooManyServersTip" xml:space="preserve">
<value>Слишком много серверов, пожалуйста, откройте главный интерфейс</value>
</data>
<data name="LabLAN" xml:space="preserve"> <data name="LabLAN" xml:space="preserve">
<value>LAN</value> <value>LAN</value>
</data> </data>
@@ -532,9 +511,6 @@
<data name="menuClearServerStatistics" xml:space="preserve"> <data name="menuClearServerStatistics" xml:space="preserve">
<value>Очистить всю статистику</value> <value>Очистить всю статистику</value>
</data> </data>
<data name="menuPingServer" xml:space="preserve">
<value>Тест на задержку сервера (Ctrl+P)</value>
</data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>Тест на реальную задержку сервера (Ctrl+R)</value> <value>Тест на реальную задержку сервера (Ctrl+R)</value>
</data> </data>
@@ -547,18 +523,12 @@
<data name="menuTcpingServer" xml:space="preserve"> <data name="menuTcpingServer" xml:space="preserve">
<value>Тест задержки с tcping (Ctrl+O)</value> <value>Тест задержки с tcping (Ctrl+O)</value>
</data> </data>
<data name="menuTestMe" xml:space="preserve">
<value>Проверить текущий статус службы</value>
</data>
<data name="menuExport2ClientConfig" xml:space="preserve"> <data name="menuExport2ClientConfig" xml:space="preserve">
<value>Экспортировать выбранный сервер для клиента</value> <value>Экспортировать выбранный сервер для клиента</value>
</data> </data>
<data name="menuExport2ShareUrl" xml:space="preserve"> <data name="menuExport2ShareUrl" xml:space="preserve">
<value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value> <value>Экспорт URL-адресов общего доступа в буфер обмена (Ctrl+C)</value>
</data> </data>
<data name="menuExport2SubContent" xml:space="preserve">
<value>Экспортировать ссылку-подписку (base64) в буфер обмена</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve"> <data name="menuAddCustomServer" xml:space="preserve">
<value>Добавить сервер пользовательской конфигурации</value> <value>Добавить сервер пользовательской конфигурации</value>
</data> </data>
@@ -589,9 +559,6 @@
<data name="menuMsgViewCopyAll" xml:space="preserve"> <data name="menuMsgViewCopyAll" xml:space="preserve">
<value>Скопировать все</value> <value>Скопировать все</value>
</data> </data>
<data name="menuMsgViewFilter" xml:space="preserve">
<value>Установить фильтры сообщений</value>
</data>
<data name="menuMsgViewSelectAll" xml:space="preserve"> <data name="menuMsgViewSelectAll" xml:space="preserve">
<value>Выбрать все (Ctrl+A)</value> <value>Выбрать все (Ctrl+A)</value>
</data> </data>
@@ -704,7 +671,7 @@
<value>txtPreSocksPort</value> <value>txtPreSocksPort</value>
</data> </data>
<data name="TipPreSocksPort" xml:space="preserve"> <data name="TipPreSocksPort" xml:space="preserve">
<value>* После установки этого значения служба socks будет запущена с использованием sing-box для обеспечения таких функций, как отображение скорости</value> <value>* После установки этого значения служба socks будет запущена с использованием Xray/sing-box(Tun) для обеспечения таких функций, как отображение скорости</value>
</data> </data>
<data name="TbBrowse" xml:space="preserve"> <data name="TbBrowse" xml:space="preserve">
<value>Просмотр</value> <value>Просмотр</value>
@@ -967,6 +934,9 @@
<data name="TbSettingsRouteOnly" xml:space="preserve"> <data name="TbSettingsRouteOnly" xml:space="preserve">
<value>Только маршрут</value> <value>Только маршрут</value>
</data> </data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>Не используйте прокси-серверы для локальных (интранет) адресов</value>
</data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>Тест задержки и скорости всех серверов (Ctrl+E)</value> <value>Тест задержки и скорости всех серверов (Ctrl+E)</value>
</data> </data>
@@ -997,21 +967,9 @@
<data name="TbSettingsTunMode" xml:space="preserve"> <data name="TbSettingsTunMode" xml:space="preserve">
<value>Настройки TunMode</value> <value>Настройки TunMode</value>
</data> </data>
<data name="TbSettingsTunModeDirectIP" xml:space="preserve">
<value>Прямой IP CIDR, разделенный запятыми (,)</value>
</data>
<data name="TbSettingsTunModeDirectProcess" xml:space="preserve">
<value>Имя процесса, разделенное запятыми (,)</value>
</data>
<data name="TbSettingsTunModeShowWindow" xml:space="preserve">
<value>Показать консоль</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve"> <data name="menuMoveToGroup" xml:space="preserve">
<value>Перейти в группу</value> <value>Перейти в группу</value>
</data> </data>
<data name="TbSettingsTunModeCustomTemplate" xml:space="preserve">
<value>Пользовательский шаблон</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve"> <data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Включить сортировку перетаскиванием сервера (требуется перезагрузка)</value> <value>Включить сортировку перетаскиванием сервера (требуется перезагрузка)</value>
</data> </data>
@@ -1045,9 +1003,6 @@
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value> <value>Скопируйте файл шрифта TTF/TTC в каталог guiFonts, перезапустите настройки</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>HTTP port=socks port+1</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve"> <data name="TbSettingsStartBootTip" xml:space="preserve">
<value>Установите это с правами администратора</value> <value>Установите это с правами администратора</value>
</data> </data>
@@ -1072,4 +1027,4 @@
<data name="TbSettingsSpeedTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>URL спидтеста</value> <value>URL спидтеста</value>
</data> </data>
</root> </root>

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