Compare commits

...

220 Commits
7.0.3 ... 7.5.1

Author SHA1 Message Date
2dust
f500d2b9f4 up 7.5.1 2025-01-01 16:25:53 +08:00
2dust
79e53bf1f5 Improve macos system proxy code 2025-01-01 14:24:23 +08:00
2dust
31de7ec094 Bug fix SetLinuxChmod 2025-01-01 12:27:49 +08:00
2dust
2e4501187c Window title display adjustment
https://github.com/2dust/v2rayN/issues/6389
2025-01-01 10:38:55 +08:00
2dust
4430c9bd74 Remove the last rule from the Whitelist
https://github.com/2dust/v2rayN/issues/6378
2024-12-31 20:37:14 +08:00
2dust
cf8be85ff7 Remove the display of run as an administrator in Linux and macos 2024-12-31 16:30:27 +08:00
2dust
0759be1223 Fix rule required
https://github.com/2dust/v2rayN/issues/6378
2024-12-31 15:32:31 +08:00
2dust
21f8ddcf9f macos adds system proxy for USB
https://github.com/2dust/v2rayN/issues/6381
2024-12-31 14:55:35 +08:00
2dust
37cba5ee34 Fix export rule order issue
https://github.com/2dust/v2rayN/issues/6377
2024-12-31 14:15:09 +08:00
OnceUponATimeInAmerica
ff642fd1ac Add full support for (one-click) Iran regional preset by using Chocolate4U's github repos for iran routing rules (#6384) 2024-12-31 13:51:06 +08:00
2dust
647f1d9c8b up 7.5.0 2024-12-30 19:56:33 +08:00
2dust
d886195ee3 Adjust upgrade waiting time 2024-12-30 19:55:32 +08:00
2dust
e2b8f4f89a If Process.start contains spaces, add quotes 2024-12-30 19:33:39 +08:00
2dust
1dcfe661e9 Modify the build script
When NotStoreConfigHere.txt file exists, the configs not stored in the current folder
2024-12-30 18:16:07 +08:00
2dust
d6dd110781 Adjust open the storage location 2024-12-30 11:10:27 +08:00
2dust
a0f956c885 Add command shortcut keys for macos
https://github.com/2dust/v2rayN/issues/6375
2024-12-30 11:02:09 +08:00
Long Yixing
88bcafed97 Modify the build macos script (#6374) 2024-12-30 09:24:22 +08:00
2dust
6e4f15ab52 Update README.md 2024-12-27 10:12:38 +08:00
Wydy
20cae1ff4d Update pac (#6356) 2024-12-27 09:48:28 +08:00
2dust
dcf621b822 Modify the build script 2024-12-26 17:19:42 +08:00
2dust
eafa20032b Modify the build windows script 2024-12-25 17:06:03 +08:00
2dust
7375e1a490 Modify the build macos script 2024-12-25 16:48:23 +08:00
2dust
199d87ba84 Modify the build linux script and add release package deb 2024-12-25 16:11:02 +08:00
2dust
b43975ebfc Add v2rayN.png for desktop 2024-12-25 16:06:11 +08:00
2dust
fe7314c978 up 7.4.2 2024-12-24 10:55:25 +08:00
2dust
d4eb8e59a6 update build 2024-12-23 17:39:50 +08:00
2dust
8ee00907b7 update build 2024-12-23 17:34:06 +08:00
2dust
25fddc3c71 Code clean for desktop 2024-12-23 14:28:33 +08:00
2dust
c78b733850 Revert "update build macos"
This reverts commit a57c83125e.
2024-12-23 13:59:55 +08:00
2dust
a57c83125e update build macos 2024-12-23 12:12:03 +08:00
2dust
247b59985f update build 2024-12-23 11:31:56 +08:00
2dust
7470b8b6d3 Try to fix
https://github.com/2dust/v2rayN/issues/6073
2024-12-23 10:38:37 +08:00
2dust
776d37b7aa Optimize port display 2024-12-23 10:37:43 +08:00
alphax-hue3682
8f532f8468 Update persian translate (#6325) 2024-12-23 10:00:51 +08:00
2dust
472963fe2d Add a second local listening port
https://github.com/2dust/v2rayN/issues/6321
2024-12-22 20:03:20 +08:00
2dust
6a9b62ab9a Improve Ctrl+V for Windows 2024-12-22 12:02:00 +08:00
2dust
9ac8aa2969 up PackageReference 2024-12-22 12:00:50 +08:00
2dust
838bd2c794 up 7.4.1 2024-12-19 16:18:45 +08:00
2dust
b2bbe432e0 Fix
https://github.com/2dust/v2rayN/issues/6309
2024-12-19 16:07:45 +08:00
2dust
b3d8042452 The lower limit of the font size from 10 to 8 2024-12-19 13:53:40 +08:00
2dust
0c758a7fdc Optimize UI for macos 2024-12-19 13:36:45 +08:00
2dust
85cb1d1c92 Bug fix system proxy for macos 2024-12-19 13:20:12 +08:00
2dust
2cd2e8894d Add system proxy exception function for macos 2024-12-19 11:40:16 +08:00
2dust
abb58379b3 Add IsNonWindows instead of IsLinux or IsOSX 2024-12-19 11:24:52 +08:00
2dust
4f48e8b190 Optimize UI 2024-12-19 10:23:46 +08:00
2dust
2b5cbb5e74 UnauthorizedAccessException to Exception 2024-12-18 15:27:00 +08:00
2dust
23dd140921 up 7.4.0 2024-12-18 14:47:27 +08:00
2dust
8c8d7bda64 StartupPath optional LocalApplicationData for linux 2024-12-18 10:27:58 +08:00
2dust
a6e246948a Linux system proxy adds kde version processing 2024-12-17 11:05:12 +08:00
2dust
c49ba735a0 Optimize code 2024-12-16 21:05:36 +08:00
2dust
1a33c598e8 Disable mux when using xhttp 2024-12-16 21:01:03 +08:00
2dust
a4bbdb49de proxy api.ip.sb
https://github.com/2dust/v2rayN/issues/6280
2024-12-16 19:59:46 +08:00
2dust
cf3846fbfd Update README.md 2024-12-16 19:47:27 +08:00
2dust
d46943eedf Optimize UI 2024-12-16 14:28:22 +08:00
2dust
3bc17bd50a Add host for xray ws
https://github.com/XTLS/Xray-core/pull/4142
2024-12-16 14:22:31 +08:00
2dust
48a159f4c8 Need SkiaSharp V2.88 2024-12-15 16:15:58 +08:00
2dust
3d1bcffdc5 up 7.3.2 2024-12-15 15:14:25 +08:00
2dust
45fa0f94d2 up PackageReference 2024-12-15 15:13:37 +08:00
2dust
ed16b7de4a Fix
https://github.com/2dust/v2rayN/issues/6258
2024-12-15 14:41:48 +08:00
2dust
f2ec03c7ec Bug fix
https://github.com/2dust/v2rayN/issues/6263
2024-12-15 14:41:29 +08:00
2dust
11db87f1e6 Remove unused resources 2024-12-15 14:27:00 +08:00
phoenix6936
a1feaf33e0 Update persian translation (#6245)
* Update persian translation

* Update ResUI.fa-Ir.resx
2024-12-15 11:24:13 +08:00
2dust
53a99e3f79 Remove part System.Reflection 2024-12-08 11:11:06 +08:00
2dust
e7f04f55c2 Remove QueryableExtension 2024-12-08 11:10:15 +08:00
2dust
6653ea12b7 Add Language: Hungarian
https://github.com/2dust/v2rayN/issues/6252
2024-12-07 21:25:53 +08:00
2dust
a28cef5b98 Fixed the issue of save window size when exit
https://github.com/2dust/v2rayN/issues/6251
2024-12-07 21:13:57 +08:00
2dust
78a28fbdb3 up 7.3.1 2024-12-07 16:30:32 +08:00
2dust
bf8bbbdcb0 Code clean 2024-12-07 16:29:58 +08:00
2dust
83ad83b135 Optimize save config files 2024-12-07 14:07:51 +08:00
2dust
dbd4f55981 Add system proxy exception function for linux
https://github.com/2dust/v2rayN/issues/6214
2024-12-06 19:12:32 +08:00
2dust
5f5d7172ee Optimize system proxy exceptions 2024-12-06 16:38:23 +08:00
2dust
fbd4557b44 WebProxy uses socks5 instead of http 2024-12-06 14:01:11 +08:00
phoenix6936
5d55a55754 Update persian translate (#6237)
* Update persian translate

* Update ResUI.fa-Ir.resx
2024-12-06 10:01:11 +08:00
phoenix6936
84032aec33 Update persian translation (#6227)
* Update persian translation

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx
2024-12-06 09:38:56 +08:00
2dust
a372d8902e up 7.3.0 2024-12-05 20:08:23 +08:00
2dust
c38c62e4c3 Add automatic batching during speed test and real ping 2024-12-05 19:48:42 +08:00
2dust
8aceff7480 Enhanced testing function
Separate xray-core and sing-box-core testing
2024-12-05 15:21:16 +08:00
2dust
736c450161 Improve the code 2024-12-05 14:05:12 +08:00
2dust
3b63a3d308 Fix
https://github.com/2dust/v2rayN/issues/6216
2024-12-05 14:04:39 +08:00
2dust
4f56174c8f Bug fix
https://github.com/2dust/v2rayN/issues/6219
2024-12-05 12:16:53 +08:00
2dust
4d2eb324f1 Adjust UI
https://github.com/2dust/v2rayN/issues/6217
2024-12-05 10:39:08 +08:00
2dust
3f2ab8ddcb Try to fix
https://github.com/2dust/v2rayN/issues/6186
2024-12-05 10:12:26 +08:00
2dust
fd8f863c5b Add stream-one for xhttp mode 2024-12-03 18:00:55 +08:00
2dust
246f1d7df0 Update README.md 2024-12-03 17:54:13 +08:00
2dust
ccacda9bf5 Using mixed local listening ports 2024-12-03 15:01:36 +08:00
2dust
5494d63878 Remove v2fly-core UI operation support 2024-12-03 13:58:56 +08:00
2dust
c32b9812a7 up PackageReference 2024-12-02 14:43:07 +08:00
2dust
9eb9898b61 Improve the clash connection 2024-12-02 14:40:09 +08:00
2dust
834e05999f Paste import functionality moved to server list
https://github.com/2dust/v2rayN/issues/6201
2024-12-02 11:01:32 +08:00
2dust
b4c37d9906 Bug fix
https://github.com/2dust/v2rayN/issues/6200
2024-12-02 10:16:07 +08:00
2dust
9326b450d7 Delete .github/workflows/winget-pre-release-publish.yml 2024-12-01 14:39:36 +08:00
2dust
019ee8b1ba Update winget-publish.yml 2024-12-01 14:30:39 +08:00
Merrick Zhang
f043645397 Create winget-publish.yml (#6014)
* Create winget-publish.yml

Publish to winget after release

* Update winget-publish.yml

change to released trigger

* Create winget-pre-release-publish.yml

publish pre-release versions.
2024-12-01 14:29:10 +08:00
2dust
3b173f0b3e Improve code 2024-12-01 11:17:36 +08:00
2dust
f36c06389d Improve the clash connection 2024-12-01 10:18:36 +08:00
2dust
d3a0b44247 Bug fix
https://github.com/2dust/v2rayN/issues/6182
2024-11-30 13:49:26 +08:00
2dust
e4d3a98aa8 Fixed the problem of traffic statistics api url 2024-11-30 10:58:53 +08:00
2dust
f685682214 Code clean 2024-11-29 19:21:09 +08:00
2dust
1c6323315b up 7.2.3 2024-11-29 11:43:53 +08:00
2dust
1ff4839be1 Bug fix
https://github.com/2dust/v2rayN/issues/6160
2024-11-29 11:31:22 +08:00
2dust
558e5bb340 Improve tun for linux 2024-11-29 10:31:57 +08:00
2dust
48a9d208e6 Label text optimization 2024-11-28 14:44:24 +08:00
2dust
f29e1f8c45 up 7.2.2 2024-11-27 18:54:16 +08:00
2dust
5d2bc88bb9 up PackageReference 2024-11-27 18:53:32 +08:00
2dust
298fdb1191 Change IPAPI
https://github.com/2dust/v2rayN/issues/6172
2024-11-27 17:03:16 +08:00
2dust
59b34688ea Improve tun for linux 2024-11-27 16:52:25 +08:00
2dust
5ce0bb6e4a Up 2024-11-27 14:40:01 +08:00
2dust
487b1ab182 Update build-osx 2024-11-27 14:37:39 +08:00
2dust
5c144a8ba3 Create build-osx.yml 2024-11-27 14:29:22 +08:00
2dust
ad344356df Create build-osx.sh 2024-11-27 14:23:16 +08:00
2dust
a55c65374d Update build.ps1 2024-11-27 14:22:42 +08:00
2dust
28447a9d43 Update build.ps1 2024-11-27 13:57:51 +08:00
2dust
0c03550c62 Update build.yml 2024-11-27 12:22:40 +08:00
2dust
6d9a84803f Update build.yml 2024-11-27 12:20:26 +08:00
2dust
03b0e4e2bb Update build.yml 2024-11-27 12:18:15 +08:00
2dust
a00e9a6f5e Update build.ps1 2024-11-27 11:25:37 +08:00
2dust
ba17f8fde9 Improve CoreHandler 2024-11-27 11:05:41 +08:00
2dust
01d35456bd Update AesUtils.cs 2024-11-26 20:07:41 +08:00
cryptochecktool
672b8c48ac AesUtils重新修改 (#6165)
* Create AesUtils.cs

新增AesUtils,替换掉DesUtils,提高安全性。
细节:
1.使用AES代替DES
2.正确使用IV调用方式
3.使用SHA256代替MD5进行密钥派生
4.使用PBKDF进行迭代生成密钥。

* Update AesUtils.cs

1.将默认密钥规则设置为与DES一致
2.经过本地测试
2024-11-26 19:54:46 +08:00
2dust
ac1a357740 Delete AesUtils.cs 2024-11-26 19:52:22 +08:00
2dust
504f8d09a6 Tun enable in macos when opening the app 2024-11-26 16:33:19 +08:00
2dust
89ce7c23c9 Fix tun interface name in macos 2024-11-26 15:32:35 +08:00
2dust
a5d99b1eb5 Improved Tun mode function in Linux version 2024-11-26 15:11:02 +08:00
2dust
800d193acb Bug fix 2024-11-26 14:39:33 +08:00
cryptochecktool
7a1d12be76 Update CoreHandler.cs (#6163)
将Desutils替换为Aesutils,提高安全性
2024-11-26 13:54:12 +08:00
cryptochecktool
1b9c95e801 Update OptionSettingViewModel.cs (#6162)
将Desutils替换为Aesutils,提升安全性。
2024-11-26 13:53:50 +08:00
cryptochecktool
9f44815470 Create AesUtils.cs (#6161)
新增AesUtils,替换掉DesUtils,提高安全性。
细节:
1.使用AES代替DES
2.正确使用IV调用方式
3.使用SHA256代替MD5进行密钥派生
4.使用PBKDF进行迭代生成密钥。
2024-11-26 13:52:37 +08:00
2dust
ca38239bce Add Font setting for macos 2024-11-25 21:00:49 +08:00
2dust
d9c22de6b8 Added core update function for macos 2024-11-25 20:31:12 +08:00
2dust
49a3c84fc5 up 7.2.1 2024-11-24 11:31:45 +08:00
2dust
5e0c28438b Refactor Localization for AmazTool 2024-11-23 14:41:19 +08:00
2dust
a6dc801bc4 Merge pac function into the main program 2024-11-23 14:08:08 +08:00
Space Time
22009d1b71 调整订阅分组设置窗口的布局 (#6132)
* 调整订阅分组设置窗口的布局

* 避免添加配置后出现滚动条
2024-11-23 10:45:16 +08:00
2dust
50f39dc40e Delete splithttp 2024-11-22 20:56:34 +08:00
2dust
05d446ed37 up 7.2.0 2024-11-22 18:04:36 +08:00
2dust
7a0b068642 Improve Follow System Theme for windows 2024-11-22 17:37:30 +08:00
2dust
c0ef8c09af Add Follow System Theme for desktop 2024-11-22 17:35:49 +08:00
fonaix
a2db6dd468 修复:TrayIcon不跟随代理模式变化的问题 (#6126)
* 添加:MacOS 代理配置与清除

* 修复:点击表头排序时,超时服务器排在前面的问题

* 添加:MacOS 打开存储所在位置功能

* 修复:删除全部节点时,UI不更新的问题

* 修复:TrayIcon不跟随代理模式变化的问题
2024-11-21 09:02:35 +08:00
2dust
471bc0f65d Update README.md 2024-11-20 15:33:29 +08:00
2dust
80f840a7c2 Fix
https://github.com/2dust/v2rayN/issues/6119
2024-11-20 15:29:06 +08:00
2dust
a2413fdf23 Remove Routing Basic function 2024-11-20 12:01:04 +08:00
2dust
9cbe2b938c Fixed the inbound issue caused by server configuration error during speed test
https://github.com/2dust/v2rayN/issues/6110
2024-11-20 10:34:51 +08:00
2dust
e915726c52 Improved upgrade
https://github.com/2dust/v2rayN/issues/6102
2024-11-20 10:29:04 +08:00
2dust
b11e68cfd8 Remove StatisticsV2rayService
Remove ProtosLib project
2024-11-19 19:20:12 +08:00
2dust
bee66d06dd Added real IP location display
https://ipapi.co/api/?shell#introduction
2024-11-19 16:43:00 +08:00
2dust
945a0add96 Code clean 2024-11-19 15:52:08 +08:00
2dust
294cabcf05 Update README.md 2024-11-18 17:14:42 +08:00
2dust
22eb993ebf up 7.1.3 2024-11-18 16:51:51 +08:00
2dust
b5e1a297ae Optimize Linux start tun mode
You can choose not to store the password and enter it manually each time
2024-11-18 16:44:12 +08:00
2dust
499a16feae Fix LocalizationHelper for AmazTool 2024-11-18 10:13:49 +08:00
Slnanx
1866a59d12 更新程序内嵌资源文件 (#6101)
* fix

* fix

* 移除自述

* 改用单例模式,避免多次初始化。

* 小修正

* 修正

* 更正自述

* 应该完成了

* 内嵌资源

* Update LocalizationHelper.cs
2024-11-18 09:57:38 +08:00
2dust
10513e0f3b Fixed the problem that the statistics column would not be hidden 2024-11-18 09:56:13 +08:00
Slnanx
2e32de2fbb fix (#6099)
* fix

* fix

* 移除自述

* 改用单例模式,避免多次初始化。

* 小修正

* 修正

* 更正自述

* 应该完成了
2024-11-17 19:42:14 +08:00
2dust
30a838df77 Bug fix
https://github.com/2dust/v2rayN/issues/6092
2024-11-17 16:18:46 +08:00
2dust
7cf9b9f57e up 7.1.2 2024-11-17 14:15:37 +08:00
2dust
736d995d4c up PackageReference 2024-11-17 14:11:51 +08:00
2dust
e335b2c0d6 Fix with AppendQuotes 2024-11-17 14:11:17 +08:00
2dust
96ae5517f6 Improve core msg 2024-11-17 09:58:57 +08:00
Slnanx
fb4b8d923a 可以通过判断系统语言来显示对应语言 (#6083) 2024-11-17 09:42:40 +08:00
2dust
2ade705e51 Bug fix 2024-11-16 20:15:05 +08:00
NagisaEfi
e0086b4b79 Update ResUI.zh-Hant.resx (#6080) 2024-11-16 10:34:55 +08:00
2dust
8f6d443104 Hide to tray when closing the window
https://github.com/2dust/v2rayN/issues/6076
2024-11-15 19:50:37 +08:00
2dust
5dbce16895 up 7.1.1 2024-11-15 13:36:44 +08:00
2dust
1016dcb3d1 Improve PAC 2024-11-15 11:59:22 +08:00
2dust
ba5ad12e13 Linux password encryption storage 2024-11-15 09:42:49 +08:00
2dust
57f9c8158e up 7.1.0 2024-11-14 15:20:14 +08:00
2dust
b8a0293b52 Add xhttp extra for xray
https://github.com/XTLS/Xray-core/pull/4000
2024-11-14 14:37:03 +08:00
2dust
59b7daaef5 Improve UI 2024-11-14 14:25:58 +08:00
2dust
d781c768e9 Add xhttp mode for xray
https://github.com/XTLS/Xray-core/pull/3994
2024-11-14 09:48:43 +08:00
2dust
04efed2079 SplitHTTP is now XHTTP for xray 2024-11-13 19:48:44 +08:00
2dust
2de9e14c7d xray-core uses quic to add failure prompts and plans to remove quic 2024-11-13 19:00:35 +08:00
2dust
a849dec6c2 Remove SagerNet 2024-11-13 18:00:31 +08:00
2dust
28019dc511 Migrate xray traffic statistics to Metrics
https://xtls.github.io/config/metrics.html
2024-11-13 16:45:23 +08:00
2dust
9d638968a9 Use tun mode without running with sudo in linux 2024-11-13 16:22:56 +08:00
2dust
f921ff7d77 Update README.md 2024-11-13 16:00:01 +08:00
NagisaEfi
e3ea329795 Update ResUI.zh-Hant.resx (#6049) 2024-11-13 09:49:41 +08:00
TTG
87f1c129b6 Update DNS Routing (#6045)
* Update DNS Routing

* Removed outdated DNS IP
2024-11-12 09:42:10 +08:00
2dust
a1c8bc0e61 Improve the code 2024-11-11 16:56:08 +08:00
fonaix
61e9101851 添加:MacOS 打开存储所在位置功能 (#6038)
* 添加:MacOS 代理配置与清除

* 修复:点击表头排序时,超时服务器排在前面的问题

* 添加:MacOS 打开存储所在位置功能

* 修复:删除全部节点时,UI不更新的问题
2024-11-11 09:48:20 +08:00
2dust
a6289347cc Bug fix
https://github.com/2dust/v2rayN/issues/6037
2024-11-11 09:37:49 +08:00
2dust
9e84de8e76 Migrating the sing-box configuration to 1.10.0
https://sing-box.sagernet.org/migration/#tun-address-fields-are-merged
2024-11-10 17:30:03 +08:00
2dust
d04cc53152 Fill ResUI 2024-11-10 17:25:36 +08:00
2dust
1ff3c5fc07 Fix
https://github.com/2dust/v2rayN/issues/6032
2024-11-10 17:24:41 +08:00
2dust
3db047a12f Fix 2024-11-09 14:37:48 +08:00
TTG
bf4615f2f2 Update Configuration to Optimize (#6027)
* Remove geolocation-cn

* Segment and update DNS lists
2024-11-09 09:28:10 +08:00
2dust
798c7fad9a up 7.0.9 2024-11-08 20:44:28 +08:00
2dust
5797b37262 Bug fix
https://github.com/2dust/v2rayN/issues/6023
2024-11-08 20:41:07 +08:00
2dust
ce22f34cd6 up 7.0.8 2024-11-08 20:01:36 +08:00
2dust
4c49e52e26 Bug fix
https://github.com/2dust/v2rayN/issues/5963
2024-11-08 19:24:36 +08:00
2dust
47318b5d70 Improve the code for Desktop Exit 2024-11-08 11:11:06 +08:00
2dust
d12297909c Improve the code for WPF Global Window 2024-11-08 11:04:03 +08:00
fonaix
5fb4edae2d 添加:MacOS 代理配置与清除 (#6018)
* 添加:MacOS 代理配置与清除

* 修复:点击表头排序时,超时服务器排在前面的问题
2024-11-08 09:21:43 +08:00
DecorativeFamily
c4b490e46d [CodeFactor] Apply fixes (#6005)
Co-authored-by: codefactor-io <support@codefactor.io>
2024-11-07 14:46:27 +08:00
2dust
45febe3fff up 7.0.7
https://github.com/2dust/v2rayN/issues/5970
2024-11-06 15:00:45 +08:00
2dust
689a81a985 Built-in font for Desktop
https://github.com/2dust/v2rayN/issues/5970
2024-11-06 14:52:54 +08:00
2dust
28620b385a Update MsgView.xaml
https://github.com/2dust/v2rayN/issues/5997
2024-11-05 19:49:27 +08:00
2dust
be13446e69 Speed ​​test address maintenance 2024-11-04 14:21:11 +08:00
2dust
ee57d5b8e6 Improve checkup date 2024-11-04 14:15:59 +08:00
2dust
4eda3dd8fa Add Memo attribute to subscription group
https://github.com/2dust/v2rayN/issues/5981
2024-11-04 10:42:42 +08:00
2dust
911dc7f90e Revert
9fd20ff001
2024-11-04 10:37:44 +08:00
fonaix
18005b96e8 修复:双击表头弹出编辑窗口的问题 (#5984)
* 修复:日志文本框垂直显示上下空白问题

* 修复:双击表头弹出编辑窗口的问题
2024-11-04 09:44:03 +08:00
2dust
a3e45d206e Bug fix
https://github.com/2dust/v2rayN/issues/5979
2024-11-03 21:15:50 +08:00
2dust
0accf262dc up 7.0.6 2024-11-03 16:49:06 +08:00
2dust
e0eb73bb0a Code clean 2024-11-03 16:45:48 +08:00
2dust
258e822c13 Add exit function to the main interface for Desktop 2024-11-03 14:48:13 +08:00
2dust
4f05b93d63 Bug fix
MainModule FileName only exists in Win32.
2024-11-03 13:44:12 +08:00
2dust
bb661d4f50 Only one instance is allowed to run 2024-11-03 13:30:32 +08:00
2dust
201cfaa922 Fix
https://github.com/2dust/v2rayN/issues/5966
2024-11-02 15:02:30 +08:00
2dust
c339aa349c up PackageReference 2024-11-02 14:42:26 +08:00
2dust
046421f345 Code clean 2024-11-02 14:42:01 +08:00
fonaix
3a2c9e7aaa 修复:日志文本框垂直显示上下空白问题 (#5967) 2024-11-02 10:28:18 +08:00
2dust
0bb6e6bd86 up 7.0.5 2024-11-01 16:54:16 +08:00
2dust
693e8ab157 Add startup auto-start for desktop 2024-11-01 14:54:23 +08:00
2dust
033c16c992 Refactor to select active nodes when updating subscriptions 2024-11-01 10:19:31 +08:00
2dust
6ec61433fb Only update the stable version of the core
https://github.com/2dust/v2rayN/issues/5950
2024-11-01 09:26:15 +08:00
2dust
072f773245 up 7.0.4 2024-10-31 09:59:59 +08:00
2dust
0086f65a96 Bug fix
b7f4fd7469
2024-10-30 08:57:10 +08:00
2dust
281f14f47e Adjustment of preset rule sets 2024-10-28 13:45:39 +08:00
2dust
9fd20ff001 De-duplication after subscription update 2024-10-28 09:38:20 +08:00
2dust
7df90a6034 Bug fix
https://github.com/2dust/v2rayN/issues/5928
2024-10-28 09:16:24 +08:00
183 changed files with 12625 additions and 3950 deletions

76
.github/workflows/build-linux.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: release Linux
on:
workflow_dispatch:
inputs:
release_tag:
required: false
type: string
push:
branches:
- master
env:
OutputArch: "linux-64"
OutputArchArm: "linux-arm64"
OutputPath64: "${{ github.workspace }}/v2rayN/Release/linux-64"
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/linux-arm64"
jobs:
build:
strategy:
matrix:
configuration: [Release]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: |
cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: v2rayN-linux
path: |
${{ github.workspace }}/v2rayN/Release/linux*
# release debian package
- name: Package debian
if: github.event.inputs.release_tag != ''
run: |
chmod 755 package-debian.sh
./package-debian.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
./package-debian.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
- name: Upload deb to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.deb
tag: ${{ github.event.inputs.release_tag }}
file_glob: true
# release zip archive
- name: Package release zip archive
if: github.event.inputs.release_tag != ''
run: |
chmod 755 package-release-zip.sh
./package-release-zip.sh $OutputArch $OutputPath64
./package-release-zip.sh $OutputArchArm $OutputPathArm64
- name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.zip
tag: ${{ github.event.inputs.release_tag }}
file_glob: true

77
.github/workflows/build-osx.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
name: release macOS
on:
workflow_dispatch:
inputs:
release_tag:
required: false
type: string
push:
branches:
- master
env:
OutputArch: "macos-64"
OutputArchArm: "macos-arm64"
OutputPath64: "${{ github.workspace }}/v2rayN/Release/macos-64"
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/macos-arm64"
jobs:
build:
strategy:
matrix:
configuration: [Release]
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: |
cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: v2rayN-macos
path: |
${{ github.workspace }}/v2rayN/Release/macos*
# release osx package
- name: Package osx
if: github.event.inputs.release_tag != ''
run: |
brew install create-dmg
chmod 755 package-osx.sh
./package-osx.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
./package-osx.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
- name: Upload dmg to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.dmg
tag: ${{ github.event.inputs.release_tag }}
file_glob: true
# release zip archive
- name: Package release zip archive
if: github.event.inputs.release_tag != ''
run: |
chmod 755 package-release-zip.sh
./package-release-zip.sh $OutputArch $OutputPath64
./package-release-zip.sh $OutputArchArm $OutputPathArm64
- name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.zip
tag: ${{ github.event.inputs.release_tag }}
file_glob: true

67
.github/workflows/build-windows.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: release Windows
on:
workflow_dispatch:
inputs:
release_tag:
required: false
type: string
push:
branches:
- master
env:
OutputArch: "windows-64"
OutputArchArm: "windows-arm64"
OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64"
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64"
OutputPath64Sc: "${{ github.workspace }}/v2rayN/Release/windows-64-SelfContained"
jobs:
build:
strategy:
matrix:
configuration: [Release]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: |
cd v2rayN
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: v2rayN-windows
path: |
${{ github.workspace }}/v2rayN/Release/windows*
# release zip archive
- name: Package release zip archive
if: github.event.inputs.release_tag != ''
run: |
chmod 755 package-release-zip.sh
./package-release-zip.sh $OutputArch $OutputPath64
./package-release-zip.sh "windows-64-With-Core" $OutputPath64
./package-release-zip.sh $OutputArchArm $OutputPathArm64
./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc
./package-release-zip.sh "windows-64-SelfContained-With-Core" $OutputPath64Sc
- name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.zip
tag: ${{ github.event.inputs.release_tag }}
file_glob: true

View File

@@ -1,60 +0,0 @@
name: release
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
strategy:
matrix:
configuration: [Release]
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
# - name: 删除工作流运行
# uses: Mattraks/delete-workflow-runs@v2
# with:
# token: ${{ github.token }}
# repository: ${{ github.repository }}
# retain_days: 0
# keep_minimum_runs: 1
- name: Build
run: cd v2rayN &&
.\build.ps1
# - name: Package
# shell: pwsh
# run: |
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: v2rayN
path: |
.\v2rayN\v2rayN.zip
# - name: Release
# uses: softprops/action-gh-release@v1
# env:
# GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
# with:
# prerelease: ${{ contains(github.ref, '-') }}
# draft: false
# files: |
# .\v2rayN\v2rayN.zip
# body: |
# [![](https://img.shields.io/badge/Telegram-Channel-blue)](https://t.me/netch_channel) [![](https://img.shields.io/badge/Telegram-Group-green)](https://t.me/netch_group)
# ## Changelogs
# * This is an automated deployment of GitHub Actions, the change log should be updated manually soon
# ## 更新日志
# * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新

31
.github/workflows/winget-publish.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: WinGet submission on release
# based off of https://github.com/nushell/nushell/blob/main/.github/workflows/winget-submission.yml
# inspired by https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml
# Modified by @MerrickZ https://github.com/anpho
on:
workflow_dispatch:
release:
types: [released]
jobs:
winget:
name: Publish winget package
runs-on: windows-latest
steps:
- name: Submit v2ray package to Windows Package Manager Community Repository
run: |
$wingetPackage = "2dust.v2rayN"
$gitToken = "${{ secrets.PT_WINGET }}"
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
$installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64-With-Core\.zip*' | Select -ExpandProperty browser_download_url
$ver = $targetRelease.tag_name
# getting latest wingetcreate file
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$installerUrl|x64" -t $gitToken

View File

@@ -1,5 +1,5 @@
# v2rayN # v2rayN
A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) A GUI client for Windows, Linux and macOS, support [Xray core](https://github.com/XTLS/Xray-core) and [sing-box-core](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master) [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master)
@@ -9,13 +9,24 @@ A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core)
## How to use ## How to use
- If you are new to this, please download v2rayN-With-Core.zip from [releases](https://github.com/2dust/v2rayN/releases) Check [Release files introduction](https://github.com/2dust/v2rayN/wiki/Release-files-introduction) and select the version you need to download
- Otherwise please download v2rayN.zip (you will also need to download cores in the bin directory) ### Windows
- Run v2rayN.exe - Run `v2rayN.exe`
### Linux
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
```
Debian 9+
Ubuntu 16.04+
Fedora 30+
```
### macOS
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
```
macOS 10.14+
```
## Requirements ## Requirements
- (6.35 and above)[Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) - [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)

53
package-debian.sh Normal file
View File

@@ -0,0 +1,53 @@
#!/bin/bash
Arch="$1"
OutputPath="$2"
Version="$3"
PackagePath="v2rayN-Package-${Arch}"
mkdir -p "${PackagePath}/DEBIAN"
mkdir -p "${PackagePath}/opt"
cp -rf $OutputPath "${PackagePath}/opt/v2rayN"
echo "When this file exists, app will not store configs under this folder" > "${PackagePath}/opt/v2rayN/NotStoreConfigHere.txt"
if [ $Arch = "linux-64" ]; then
Arch2="amd64"
else
Arch2="arm64"
fi
echo $Arch2
# basic
cat >"${PackagePath}/DEBIAN/control" <<-EOF
Package: v2rayN
Version: $Version
Architecture: $Arch2
Maintainer: https://github.com/2dust/v2rayN
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
EOF
cat >"${PackagePath}/DEBIAN/postinst" <<-EOF
if [ ! -s /usr/share/applications/v2rayN.desktop ]; then
cat >/usr/share/applications/v2rayN.desktop<<-END
[Desktop Entry]
Name=v2rayN
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
Exec=/opt/v2rayN/v2rayN
Icon=/opt/v2rayN/v2rayN.png
Terminal=false
Type=Application
Categories=Network;Application;
END
fi
update-desktop-database
EOF
sudo chmod 0755 "${PackagePath}/DEBIAN/postinst"
sudo chmod 0755 "${PackagePath}/opt/v2rayN/v2rayN"
sudo chmod 0755 "${PackagePath}/opt/v2rayN/AmazTool"
# desktop && PATH
sudo dpkg-deb -Zxz --build $PackagePath
sudo mv "${PackagePath}.deb" "v2rayN-${Arch}.deb"

65
package-osx.sh Executable file
View File

@@ -0,0 +1,65 @@
#!/bin/bash
Arch="$1"
OutputPath="$2"
Version="$3"
PackagePath="v2rayN-Package-${Arch}"
mkdir -p "$PackagePath/v2rayN.app/Contents/Resources"
cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS"
echo "When this file exists, app will not store configs under this folder" > "$PackagePath/v2rayN.app/Contents/MacOS/NotStoreConfigHere.txt"
chmod +x "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN"
mkdir -p "$PackagePath/icons.iconset"
sips -z 16 16 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_16x16.png"
sips -z 32 32 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_16x16@2x.png"
sips -z 32 32 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_32x32.png"
sips -z 64 64 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_32x32@2x.png"
sips -z 128 128 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_128x128.png"
sips -z 256 256 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_128x128@2x.png"
sips -z 256 256 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_256x256.png"
sips -z 512 512 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_256x256@2x.png"
sips -z 512 512 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_512x512.png"
sips -z 1024 1024 "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.png" --out "$PackagePath/icons.iconset/icon_512x512@2x.png"
iconutil -c icns "$PackagePath/icons.iconset" -o "$PackagePath/v2rayN.app/Contents/Resources/AppIcon.icns"
cat >"$PackagePath/v2rayN.app/Contents/Info.plist" <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>v2rayN</string>
<key>CFBundleExecutable</key>
<string>v2rayN</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>2dust.v2rayN</string>
<key>CFBundleName</key>
<string>v2rayN</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${Version}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
EOF
create-dmg \
--volname "v2rayN Installer" \
--window-size 700 420 \
--icon-size 100 \
--icon "v2rayN.app" 160 185 \
--hide-extension "v2rayN.app" \
--app-drop-link 500 185 \
"v2rayN-${Arch}.dmg" \
"$PackagePath/v2rayN.app"

15
package-release-zip.sh Normal file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
Arch="$1"
OutputPath="$2"
OutputArch="v2rayN-${Arch}"
FileName="v2rayN-${Arch}.zip"
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
ZipPath64="./$OutputArch"
mkdir $ZipPath64
cp -rf $OutputPath "$ZipPath64/$OutputArch"
7z a -tZip $FileName "$ZipPath64/$OutputArch" -mx1

View File

@@ -6,7 +6,22 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright> <Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
<FileVersion>1.3.0</FileVersion> <FileVersion>1.3.1</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Update="Resx\Resource.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resource.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resx\Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project> </Project>

View File

@@ -10,7 +10,7 @@
{ {
if (args.Length == 0) if (args.Length == 0)
{ {
Console.WriteLine("Please run it from the main application.(请从主应用运行)"); Console.WriteLine(Resx.Resource.Guidelines);
Thread.Sleep(5000); Thread.Sleep(5000);
return; return;
} }

171
v2rayN/AmazTool/Resx/Resource.Designer.cs generated Normal file
View File

@@ -0,0 +1,171 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace AmazTool.Resx {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resource {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resource() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AmazTool.Resx.Resource", typeof(Resource).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似 Failed to terminate the v2rayN.Close it manually,or the upgrade may fail. 的本地化字符串。
/// </summary>
internal static string FailedTerminateProcess {
get {
return ResourceManager.GetString("FailedTerminateProcess", resourceCulture);
}
}
/// <summary>
/// 查找类似 Failed to extract the update package. 的本地化字符串。
/// </summary>
internal static string FailedUnzipping {
get {
return ResourceManager.GetString("FailedUnzipping", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upgrade failed. 的本地化字符串。
/// </summary>
internal static string FailedUpgrade {
get {
return ResourceManager.GetString("FailedUpgrade", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please run it from the main application. 的本地化字符串。
/// </summary>
internal static string Guidelines {
get {
return ResourceManager.GetString("Guidelines", resourceCulture);
}
}
/// <summary>
/// 查找类似 Information 的本地化字符串。
/// </summary>
internal static string Information {
get {
return ResourceManager.GetString("Information", resourceCulture);
}
}
/// <summary>
/// 查找类似 In progress, please wait... 的本地化字符串。
/// </summary>
internal static string InProgress {
get {
return ResourceManager.GetString("InProgress", resourceCulture);
}
}
/// <summary>
/// 查找类似 Start v2rayN, please wait... 的本地化字符串。
/// </summary>
internal static string Restartv2rayN {
get {
return ResourceManager.GetString("Restartv2rayN", resourceCulture);
}
}
/// <summary>
/// 查找类似 Start extracting the update package... 的本地化字符串。
/// </summary>
internal static string StartUnzipping {
get {
return ResourceManager.GetString("StartUnzipping", resourceCulture);
}
}
/// <summary>
/// 查找类似 Successfully extracted the update package. 的本地化字符串。
/// </summary>
internal static string SuccessUnzipping {
get {
return ResourceManager.GetString("SuccessUnzipping", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upgrade success. 的本地化字符串。
/// </summary>
internal static string SuccessUpgrade {
get {
return ResourceManager.GetString("SuccessUpgrade", resourceCulture);
}
}
/// <summary>
/// 查找类似 Try to terminate the v2rayN process... 的本地化字符串。
/// </summary>
internal static string TryTerminateProcess {
get {
return ResourceManager.GetString("TryTerminateProcess", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upgrade failed, file not found. 的本地化字符串。
/// </summary>
internal static string UpgradeFileNotFound {
get {
return ResourceManager.GetString("UpgradeFileNotFound", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Restartv2rayN" xml:space="preserve">
<value>Start v2rayN, please wait...</value>
</data>
<data name="Guidelines" xml:space="preserve">
<value>Please run it from the main application.</value>
</data>
<data name="UpgradeFileNotFound" xml:space="preserve">
<value>Upgrade failed, file not found.</value>
</data>
<data name="InProgress" xml:space="preserve">
<value>In progress, please wait...</value>
</data>
<data name="TryTerminateProcess" xml:space="preserve">
<value>Try to terminate the v2rayN process...</value>
</data>
<data name="FailedTerminateProcess" xml:space="preserve">
<value>Failed to terminate the v2rayN.Close it manually,or the upgrade may fail.</value>
</data>
<data name="StartUnzipping" xml:space="preserve">
<value>Start extracting the update package...</value>
</data>
<data name="SuccessUnzipping" xml:space="preserve">
<value>Successfully extracted the update package.</value>
</data>
<data name="FailedUnzipping" xml:space="preserve">
<value>Failed to extract the update package.</value>
</data>
<data name="FailedUpgrade" xml:space="preserve">
<value>Upgrade failed.</value>
</data>
<data name="SuccessUpgrade" xml:space="preserve">
<value>Upgrade success.</value>
</data>
<data name="Information" xml:space="preserve">
<value>Information</value>
</data>
</root>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@@ -117,8 +117,40 @@
<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>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <data name="Restartv2rayN" xml:space="preserve">
<data name="pac" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>正在重启,请等待...</value>
<value>Resources\pac.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value> </data>
<data name="Guidelines" xml:space="preserve">
<value>请从主应用运行。</value>
</data>
<data name="UpgradeFileNotFound" xml:space="preserve">
<value>升级失败,文件不存在。</value>
</data>
<data name="InProgress" xml:space="preserve">
<value>正在进行中,请等待...</value>
</data>
<data name="TryTerminateProcess" xml:space="preserve">
<value>尝试结束 v2rayN 进程...</value>
</data>
<data name="FailedTerminateProcess" xml:space="preserve">
<value>请手动关闭正在运行的v2rayN否则可能升级失败。</value>
</data>
<data name="StartUnzipping" xml:space="preserve">
<value>开始解压缩更新包...</value>
</data>
<data name="SuccessUnzipping" xml:space="preserve">
<value>解压缩更新包成功。</value>
</data>
<data name="FailedUnzipping" xml:space="preserve">
<value>解压缩更新包失败。</value>
</data>
<data name="FailedUpgrade" xml:space="preserve">
<value>升级失败。</value>
</data>
<data name="SuccessUpgrade" xml:space="preserve">
<value>升级成功。</value>
</data>
<data name="Information" xml:space="preserve">
<value>提示</value>
</data> </data>
</root> </root>

View File

@@ -8,35 +8,37 @@ namespace AmazTool
{ {
public static void Upgrade(string fileName) public static void Upgrade(string fileName)
{ {
Console.WriteLine(fileName); Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
Console.WriteLine("In progress, please wait...(正在进行中,请等待)");
Thread.Sleep(9000); Waiting(8);
if (!File.Exists(fileName)) if (!File.Exists(fileName))
{ {
Console.WriteLine("Upgrade Failed, File Not Exist(升级失败,文件不存在)."); Console.WriteLine(Resx.Resource.UpgradeFileNotFound);
return; return;
} }
Console.WriteLine("Try to end the process(尝试结束进程)."); Console.WriteLine(Resx.Resource.TryTerminateProcess);
try try
{ {
var path = GetPath(V2rayN);
Console.WriteLine(path);
var existing = Process.GetProcessesByName(V2rayN); var existing = Process.GetProcessesByName(V2rayN);
var pp = existing.FirstOrDefault(p => p.MainModule?.FileName != null && p.MainModule?.FileName.Contains(path) == true); foreach (var pp in existing)
pp?.Kill(); {
pp?.WaitForExit(1000); var path = pp.MainModule?.FileName ?? "";
if (path.StartsWith(GetPath(V2rayN)))
{
pp?.Kill();
pp?.WaitForExit(1000);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
// Access may be denied without admin right. The user may not be an administrator. // Access may be denied without admin right. The user may not be an administrator.
Console.WriteLine("Failed to close v2rayN(关闭v2rayN失败).\n" + Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace);
} }
Console.WriteLine("Start extracting files(开始解压文件)."); Console.WriteLine(Resx.Resource.StartUnzipping);
StringBuilder sb = new(); StringBuilder sb = new();
try try
{ {
@@ -79,17 +81,17 @@ namespace AmazTool
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("Upgrade Failed(升级失败)." + ex.StackTrace); Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
//return; //return;
} }
if (sb.Length > 0) if (sb.Length > 0)
{ {
Console.WriteLine("Upgrade Failed(升级失败)." + sb.ToString()); Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
//return; //return;
} }
Console.WriteLine("Start v2rayN, please wait...(正在重启,请等待)"); Console.WriteLine(Resx.Resource.Restartv2rayN);
Thread.Sleep(9000); Waiting(3);
Process process = new() Process process = new()
{ {
StartInfo = new() StartInfo = new()
@@ -122,6 +124,15 @@ namespace AmazTool
return Path.Combine(startupPath, fileName); return Path.Combine(startupPath, fileName);
} }
private static void Waiting(int second)
{
for (var i = second; i > 0; i--)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
}
private static string V2rayN => "v2rayN"; private static string V2rayN => "v2rayN";
} }
} }

View File

@@ -1,101 +0,0 @@
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace PacLib;
public class PacHandler
{
private static string _configPath;
private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static string _pacText;
private static bool _isRunning;
private static bool _needRestart = true;
public static void Start(string configPath, int httpPort, int pacPort)
{
_needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
_configPath = configPath;
_httpPort = httpPort;
_pacPort = pacPort;
InitText();
if (_needRestart)
{
Stop();
RunListener();
}
}
private static void InitText()
{
var path = Path.Combine(_configPath, "pac.txt");
if (!File.Exists(path))
{
File.AppendAllText(path, Resources.ResourceManager.GetString("pac"));
}
_pacText = File.ReadAllText(path).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
}
private static void RunListener()
{
_tcpListener = TcpListener.Create(_pacPort);
_isRunning = true;
_tcpListener.Start();
Task.Factory.StartNew(async () =>
{
while (_isRunning)
{
try
{
if (!_tcpListener.Pending())
{
await Task.Delay(10);
continue;
}
var client = _tcpListener.AcceptTcpClient();
await Task.Run(() =>
{
var stream = client.GetStream();
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText));
sb.AppendLine();
sb.Append(_pacText);
var content = Encoding.UTF8.GetBytes(sb.ToString());
stream.Write(content, 0, content.Length);
stream.Flush();
});
}
catch
{
// ignored
}
}
}, TaskCreationOptions.LongRunning);
}
public static void Stop()
{
if (_tcpListener == null) return;
try
{
_isRunning = false;
_tcpListener.Stop();
_tcpListener = null;
}
catch
{
// ignored
}
}
}

View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Update="Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<EmbeddedResource Update="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -1,95 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace PacLib {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PacLib.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似 var proxy = &apos;__PROXY__&apos;;
///var rules = [
/// [
/// [],
/// []
/// ],
/// [
/// [
/// &quot;aftygh.gov.tw&quot;,
/// &quot;aide.gov.tw&quot;,
/// &quot;aliyun.com&quot;,
/// &quot;arte.gov.tw&quot;,
/// &quot;baidu.com&quot;,
/// &quot;chinaso.com&quot;,
/// &quot;chinaz.com&quot;,
/// &quot;chukuang.gov.tw&quot;,
/// &quot;cycab.gov.tw&quot;,
/// &quot;dbnsa.gov.tw&quot;,
/// &quot;df.gov.tw&quot;,
/// &quot;eastcoast-nsa.gov.tw&quot;,
/// &quot;erv-nsa.gov.tw&quot;,
/// &quot;grb.gov.tw&quot;,
/// &quot;haosou.com&quot;,
/// [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string pac {
get {
return ResourceManager.GetString("pac", resourceCulture);
}
}
}
}

View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Statistics.proto" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.28.3" />
<PackageReference Include="Grpc.Net.Client" Version="2.66.0" />
<PackageReference Include="Grpc.Tools" Version="2.67.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -1,53 +0,0 @@
syntax = "proto3";
package v2ray.core.app.stats.command;
option csharp_namespace = "ProtosLib.Statistics";
message GetStatsRequest {
// Name of the stat counter.
string name = 1;
// Whether or not to reset the counter to fetching its value.
bool reset = 2;
}
message Stat {
string name = 1;
int64 value = 2;
}
message GetStatsResponse {
Stat stat = 1;
}
message QueryStatsRequest {
string pattern = 1;
bool reset = 2;
}
message QueryStatsResponse {
repeated Stat stat = 1;
}
message SysStatsRequest {
}
message SysStatsResponse {
uint32 NumGoroutine = 1;
uint32 NumGC = 2;
uint64 Alloc = 3;
uint64 TotalAlloc = 4;
uint64 Sys = 5;
uint64 Mallocs = 6;
uint64 Frees = 7;
uint64 LiveObjects = 8;
uint64 PauseTotalNs = 9;
uint32 Uptime = 10;
}
service StatsService {
rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
}
message Config {}

View File

@@ -1,13 +0,0 @@
using ProtosLib.Statistics;
namespace ProtosLib
{
public class Tests
{
private StatsService.StatsServiceClient client_;
public Tests()
{
}
}
}

View File

@@ -0,0 +1,101 @@
using System.Security.Cryptography;
using System.Text;
namespace ServiceLib.Common
{
public class AesUtils
{
private const int KeySize = 256; // AES-256
private const int IvSize = 16; // AES block size
private const int Iterations = 10000;
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' ')); // google浏览器默认盐值
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
/// <summary>
/// Encrypt
/// </summary>
/// <param name="text">Plain text</param>
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
/// <returns>Base64 encoded cipher text with IV</returns>
public static string Encrypt(string text, string? password = null)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
var plaintext = Encoding.UTF8.GetBytes(text);
var key = GetKey(password);
var iv = GenerateIv();
using var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
using var ms = new MemoryStream();
ms.Write(iv, 0, iv.Length);
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(plaintext, 0, plaintext.Length);
cs.FlushFinalBlock();
}
var cipherTextWithIv = ms.ToArray();
return Convert.ToBase64String(cipherTextWithIv);
}
/// <summary>
/// Decrypt
/// </summary>
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
/// <returns>Plain text</returns>
public static string Decrypt(string cipherTextWithIv, string? password = null)
{
if (string.IsNullOrEmpty(cipherTextWithIv))
return string.Empty;
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
var key = GetKey(password);
var iv = new byte[IvSize];
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
using var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
using var ms = new MemoryStream();
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherText, 0, cipherText.Length);
cs.FlushFinalBlock();
}
var plainText = ms.ToArray();
return Encoding.UTF8.GetString(plainText);
}
private static byte[] GetKey(string? password)
{
if (password.IsNullOrEmpty())
{
password = DefaultPassword;
}
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
return pbkdf2.GetBytes(KeySize / 8);
}
private static byte[] GenerateIv()
{
var randomNumber = new byte[IvSize];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return randomNumber;
}
}
}

View File

@@ -0,0 +1,75 @@
using System.Security.Cryptography;
using System.Text;
namespace ServiceLib.Common
{
public class DesUtils
{
/// <summary>
/// Encrypt
/// </summary>
/// <param name="text"></param>
/// /// <param name="key"></param>
/// <returns></returns>
public static string Encrypt(string? text, string? key = null)
{
if (text.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
using var sWriter = new StreamWriter(cryStream);
sWriter.Write(text);
sWriter.Flush();
cryStream.FlushFinalBlock();
memStream.Flush();
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
}
/// <summary>
/// Decrypt
/// </summary>
/// <param name="encryptText"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Decrypt(string? encryptText, string? key = null)
{
if (encryptText.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
var buffer = Convert.FromBase64String(encryptText);
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
cryStream.Write(buffer, 0, buffer.Length);
cryStream.FlushFinalBlock();
return Encoding.UTF8.GetString(memStream.ToArray());
}
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
{
if (key.IsNullOrEmpty())
{
throw new ArgumentNullException("The key cannot be null");
}
if (key.Length <= 8)
{
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
}
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
}
private static string GetDefaultKey()
{
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Mime; using System.Net.Mime;
using System.Text; using System.Text;
@@ -10,7 +10,7 @@ namespace ServiceLib.Common
{ {
private static readonly Lazy<HttpClientHelper> _instance = new(() => private static readonly Lazy<HttpClientHelper> _instance = new(() =>
{ {
HttpClientHandler handler = new() { UseCookies = false }; SocketsHttpHandler handler = new() { UseCookies = false };
HttpClientHelper helper = new(new HttpClient(handler)); HttpClientHelper helper = new(new HttpClient(handler));
return helper; return helper;
}); });
@@ -98,7 +98,7 @@ namespace ServiceLib.Common
totalRead += read; totalRead += read;
if (read == 0) break; if (read == 0) break;
await file.WriteAsync(buffer, 0, read, token); await file.WriteAsync(buffer.AsMemory(0, read), token);
if (canReportProgress) if (canReportProgress)
{ {

View File

@@ -70,8 +70,9 @@ namespace ServiceLib.Common
/// </summary> /// </summary>
/// <param name="obj"></param> /// <param name="obj"></param>
/// <param name="indented"></param> /// <param name="indented"></param>
/// <param name="nullValue"></param>
/// <returns></returns> /// <returns></returns>
public static string Serialize(object? obj, bool indented = true) public static string Serialize(object? obj, bool indented = true, bool nullValue = false)
{ {
var result = string.Empty; var result = string.Empty;
try try
@@ -82,8 +83,8 @@ namespace ServiceLib.Common
} }
var options = new JsonSerializerOptions var options = new JsonSerializerOptions
{ {
WriteIndented = indented ? true : false, WriteIndented = indented,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
}; };
result = JsonSerializer.Serialize(obj, options); result = JsonSerializer.Serialize(obj, options);
} }
@@ -100,38 +101,5 @@ namespace ServiceLib.Common
/// <param name="obj"></param> /// <param name="obj"></param>
/// <returns></returns> /// <returns></returns>
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj); 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 var 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

@@ -37,40 +37,41 @@ namespace ServiceLib.Common
foreach (var filePath in files) foreach (var filePath in files)
{ {
var file = new FileInfo(filePath); var file = new FileInfo(filePath);
if (file.CreationTime < now) if (file.CreationTime >= now) continue;
try
{ {
try file.Delete();
{ }
file.Delete(); catch
} {
catch { } // ignored
} }
} }
} }
catch { } catch
{
// ignored
}
}); });
} }
public static void SaveLog(string strContent) public static void SaveLog(string strContent)
{ {
if (LogManager.IsLoggingEnabled()) if (!LogManager.IsLoggingEnabled()) return;
{
var logger = LogManager.GetLogger("Log1"); LogManager.GetLogger("Log1").Info(strContent);
logger.Info(strContent);
}
} }
public static void SaveLog(string strTitle, Exception ex) public static void SaveLog(string strTitle, Exception ex)
{ {
if (LogManager.IsLoggingEnabled()) if (!LogManager.IsLoggingEnabled()) return;
var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace);
if (ex?.InnerException != null)
{ {
var logger = LogManager.GetLogger("Log2"); logger.Error(ex.InnerException);
logger.Debug($"{strTitle},{ex.Message}");
logger.Debug(ex.StackTrace);
if (ex?.InnerException != null)
{
logger.Error(ex.InnerException);
}
} }
} }
} }

View File

@@ -1,50 +0,0 @@
using System.Linq.Expressions;
using System.Reflection;
namespace ServiceLib.Common
{
public static class QueryableExtension
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName)
{
return _OrderBy<T>(query, propertyName, false);
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName)
{
return _OrderBy<T>(query, propertyName, true);
}
private static IOrderedQueryable<T> _OrderBy<T>(IQueryable<T> query, string propertyName, bool isDesc)
{
var methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal";
var memberProp = typeof(T).GetProperty(propertyName);
var method = typeof(QueryableExtension).GetMethod(methodname)
.MakeGenericMethod(typeof(T), memberProp.PropertyType);
return (IOrderedQueryable<T>)method.Invoke(null, new object[] { query, memberProp });
}
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
{//public
return query.OrderBy(_GetLambda<T, TProp>(memberProperty));
}
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
{//public
return query.OrderByDescending(_GetLambda<T, TProp>(memberProperty));
}
private static Expression<Func<T, TProp>> _GetLambda<T, TProp>(PropertyInfo memberProperty)
{
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
var thisArg = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
return lambda;
}
}
}

View File

@@ -31,8 +31,8 @@
var parts = this.version.Split('.'); var parts = this.version.Split('.');
if (parts.Length == 2) if (parts.Length == 2)
{ {
this.major = int.Parse(parts[0]); this.major = int.Parse(parts.First());
this.minor = int.Parse(parts[1]); this.minor = int.Parse(parts.Last());
this.patch = 0; this.patch = 0;
} }
else if (parts.Length is 3 or 4) else if (parts.Length is 3 or 4)

View File

@@ -22,7 +22,7 @@ namespace ServiceLib.Common
public static bool BeginWithAny(this string s, IEnumerable<char> chars) public static bool BeginWithAny(this string s, IEnumerable<char> chars)
{ {
if (s.IsNullOrEmpty()) return false; if (s.IsNullOrEmpty()) return false;
return chars.Contains(s[0]); return chars.Contains(s.First());
} }
private static bool IsWhiteSpace(this string value) private static bool IsWhiteSpace(this string value)
@@ -61,7 +61,7 @@ namespace ServiceLib.Common
return string.Empty; return string.Empty;
} }
return char.ToUpper(value[0]) + value[1..]; return char.ToUpper(value.First()) + value[1..];
} }
public static string AppendQuotes(this string value) public static string AppendQuotes(this string value)

View File

@@ -1,4 +1,4 @@
using CliWrap; using CliWrap;
using CliWrap.Buffered; using CliWrap.Buffered;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
@@ -38,6 +38,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return result; return result;
} }
@@ -58,6 +59,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return null; return null;
} }
@@ -92,6 +94,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return string.Empty; return string.Empty;
} }
@@ -116,6 +119,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return null; return null;
} }
@@ -137,6 +141,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return null; return null;
} }
@@ -156,6 +161,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog("Base64Encode", ex); Logging.SaveLog("Base64Encode", ex);
} }
return string.Empty; return string.Empty;
} }
@@ -170,16 +176,16 @@ namespace ServiceLib.Common
{ {
if (plainText.IsNullOrEmpty()) return ""; if (plainText.IsNullOrEmpty()) return "";
plainText = plainText.Trim() plainText = plainText.Trim()
.Replace(Environment.NewLine, "") .Replace(Environment.NewLine, "")
.Replace("\n", "") .Replace("\n", "")
.Replace("\r", "") .Replace("\r", "")
.Replace('_', '/') .Replace('_', '/')
.Replace('-', '+') .Replace('-', '+')
.Replace(" ", ""); .Replace(" ", "");
if (plainText.Length % 4 > 0) if (plainText.Length % 4 > 0)
{ {
plainText = plainText.PadRight(plainText.Length + 4 - plainText.Length % 4, '='); plainText = plainText.PadRight(plainText.Length + 4 - (plainText.Length % 4), '=');
} }
var data = Convert.FromBase64String(plainText); var data = Convert.FromBase64String(plainText);
@@ -189,6 +195,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog("Base64Decode", ex); Logging.SaveLog("Base64Decode", ex);
} }
return string.Empty; return string.Empty;
} }
@@ -251,14 +258,17 @@ namespace ServiceLib.Common
unit = "TB"; unit = "TB";
return; return;
} }
result = GBs + ((MBs % factor) / (factor + 0.0)); result = GBs + ((MBs % factor) / (factor + 0.0));
unit = "GB"; unit = "GB";
return; return;
} }
result = MBs + ((KBs % factor) / (factor + 0.0)); result = MBs + ((KBs % factor) / (factor + 0.0));
unit = "MB"; unit = "MB";
return; return;
} }
result = KBs + ((amount % factor) / (factor + 0.0)); result = KBs + ((amount % factor) / (factor + 0.0));
unit = "KB"; unit = "KB";
return; return;
@@ -302,8 +312,9 @@ namespace ServiceLib.Common
{ {
continue; continue;
} }
var key = Uri.UnescapeDataString(keyValue[0]);
var val = Uri.UnescapeDataString(keyValue[1]); var key = Uri.UnescapeDataString(keyValue.First());
var val = Uri.UnescapeDataString(keyValue.Last());
if (result[key] is null) if (result[key] is null)
{ {
@@ -323,6 +334,7 @@ namespace ServiceLib.Common
{ {
sb.Append(b.ToString("x2")); sb.Append(b.ToString("x2"));
} }
return sb.ToString(); return sb.ToString();
} }
@@ -337,6 +349,7 @@ namespace ServiceLib.Common
{ {
return url; return url;
} }
try try
{ {
Uri uri = new(url); Uri uri = new(url);
@@ -368,6 +381,7 @@ namespace ServiceLib.Common
{ {
return text; return text;
} }
return text.Replace("", ",").Replace(Environment.NewLine, ","); return text.Replace("", ",").Replace(Environment.NewLine, ",");
} }
@@ -391,6 +405,7 @@ namespace ServiceLib.Common
{ {
return true; return true;
} }
return text == "null"; return text == "null";
} }
@@ -424,6 +439,7 @@ namespace ServiceLib.Common
_ => false, _ => false,
}; };
} }
return false; return false;
} }
@@ -448,6 +464,7 @@ namespace ServiceLib.Common
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true; if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true;
if (ipBytes[0] == 192 && ipBytes[1] == 168) return true; if (ipBytes[0] == 192 && ipBytes[1] == 168) return true;
} }
return false; return false;
} }
@@ -468,6 +485,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return false; return false;
} }
@@ -489,6 +507,7 @@ namespace ServiceLib.Common
catch catch
{ {
} }
return 59090; return 59090;
} }
@@ -498,7 +517,7 @@ namespace ServiceLib.Common
public static bool UpgradeAppExists(out string fileName) public static bool UpgradeAppExists(out string fileName)
{ {
fileName = Path.Combine(Utils.StartupPath(), GetExeName("AmazTool")); fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, GetExeName("AmazTool"));
return File.Exists(fileName); return File.Exists(fileName);
} }
@@ -510,19 +529,15 @@ namespace ServiceLib.Common
{ {
try try
{ {
if (blFull) return blFull
{ ? $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture}"
return $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture} - {File.GetLastWriteTime(GetExePath()):yyyy/MM/dd}"; : $"{Global.AppName}/{GetVersionInfo()}";
}
else
{
return $"{Global.AppName}/{GetVersionInfo()}";
}
} }
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return Global.AppName; return Global.AppName;
} }
@@ -539,6 +554,11 @@ namespace ServiceLib.Common
} }
} }
public static string GetRuntimeInfo()
{
return $"{Utils.GetVersion()} | {Utils.StartupPath()} | {Utils.GetExePath()} | {Environment.OSVersion} | {(Environment.Is64BitOperatingSystem ? 64 : 32)}";
}
/// <summary> /// <summary>
/// 取得GUID /// 取得GUID
/// </summary> /// </summary>
@@ -560,6 +580,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return string.Empty; return string.Empty;
} }
@@ -572,7 +593,14 @@ namespace ServiceLib.Common
{ {
try try
{ {
if (fileName.IsNullOrEmpty()) { return; } if (fileName.IsNullOrEmpty())
{
return;
}
if (fileName.Contains(' ')) fileName = fileName.AppendQuotes();
if (arguments.Contains(' ')) arguments = arguments.AppendQuotes();
Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true }); Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true });
} }
catch (Exception ex) catch (Exception ex)
@@ -596,8 +624,8 @@ namespace ServiceLib.Common
{ {
if (host.StartsWith("#")) continue; if (host.StartsWith("#")) continue;
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (hostItem.Length < 2) continue; if (hostItem.Length != 2) continue;
systemHosts.Add(hostItem[1], hostItem[0]); systemHosts.Add(hostItem.Last(), hostItem.First());
} }
} }
} }
@@ -605,6 +633,7 @@ namespace ServiceLib.Common
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
} }
return systemHosts; return systemHosts;
} }
@@ -629,17 +658,20 @@ namespace ServiceLib.Common
cmd = cmd.WithArguments(args); cmd = cmd.WithArguments(args);
} }
} }
var result = await cmd.ExecuteBufferedAsync(); var result = await cmd.ExecuteBufferedAsync();
if (result.IsSuccess) if (result.IsSuccess)
{ {
return result.StandardOutput.ToString(); return result.StandardOutput.ToString();
} }
Logging.SaveLog(result.ToString() ?? ""); Logging.SaveLog(result.ToString() ?? "");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog("GetCliWrapOutput", ex); Logging.SaveLog("GetCliWrapOutput", ex);
} }
return null; return null;
} }
@@ -647,6 +679,33 @@ namespace ServiceLib.Common
#region TempPath #region TempPath
public static bool HasWritePermission()
{
try
{
//When this file exists, it is equivalent to having no permission to read and write
if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "NotStoreConfigHere.txt")))
{
return false;
}
var tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "guiTemps");
if (!Directory.Exists(tempPath))
{
Directory.CreateDirectory(tempPath);
}
var fileName = Path.Combine(tempPath, GetGuid());
File.Create(fileName).Close();
File.Delete(fileName);
}
catch (Exception)
{
return false;
}
return true;
}
public static string GetPath(string fileName) public static string GetPath(string fileName)
{ {
var startupPath = StartupPath(); var startupPath = StartupPath();
@@ -654,6 +713,7 @@ namespace ServiceLib.Common
{ {
return startupPath; return startupPath;
} }
return Path.Combine(startupPath, fileName); return Path.Combine(startupPath, fileName);
} }
@@ -664,6 +724,11 @@ namespace ServiceLib.Common
public static string StartupPath() public static string StartupPath()
{ {
if (Utils.IsNonWindows() && Environment.GetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA") == "1")
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "v2rayN");
}
return AppDomain.CurrentDomain.BaseDirectory; return AppDomain.CurrentDomain.BaseDirectory;
} }
@@ -674,6 +739,7 @@ namespace ServiceLib.Common
{ {
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
} }
if (IsNullOrEmpty(filename)) if (IsNullOrEmpty(filename))
{ {
return tempPath; return tempPath;
@@ -691,6 +757,7 @@ namespace ServiceLib.Common
{ {
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
} }
return Path.Combine(tempPath, filename); return Path.Combine(tempPath, filename);
} }
@@ -701,6 +768,7 @@ namespace ServiceLib.Common
{ {
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
} }
if (Utils.IsNullOrEmpty(filename)) if (Utils.IsNullOrEmpty(filename))
{ {
return tempPath; return tempPath;
@@ -718,6 +786,7 @@ namespace ServiceLib.Common
{ {
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
} }
if (coreType != null) if (coreType != null)
{ {
tempPath = Path.Combine(tempPath, coreType.ToLower().ToString()); tempPath = Path.Combine(tempPath, coreType.ToLower().ToString());
@@ -726,6 +795,7 @@ namespace ServiceLib.Common
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
} }
} }
if (IsNullOrEmpty(filename)) if (IsNullOrEmpty(filename))
{ {
return tempPath; return tempPath;
@@ -743,6 +813,7 @@ namespace ServiceLib.Common
{ {
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
} }
if (Utils.IsNullOrEmpty(filename)) if (Utils.IsNullOrEmpty(filename))
{ {
return tempPath; return tempPath;
@@ -760,6 +831,7 @@ namespace ServiceLib.Common
{ {
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
} }
if (Utils.IsNullOrEmpty(filename)) if (Utils.IsNullOrEmpty(filename))
{ {
return tempPath; return tempPath;
@@ -780,6 +852,8 @@ namespace ServiceLib.Common
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static bool IsNonWindows() => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static string GetExeName(string name) public static string GetExeName(string name)
{ {
return IsWindows() ? $"{name}.exe" : name; return IsWindows() ? $"{name}.exe" : name;
@@ -791,18 +865,19 @@ namespace ServiceLib.Common
{ {
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
} }
else return false;
{ //else
var id = GetLinuxUserId().Result ?? "1000"; //{
if (int.TryParse(id, out var userId)) // var id = GetLinuxUserId().Result ?? "1000";
{ // if (int.TryParse(id, out var userId))
return userId == 0; // {
} // return userId == 0;
else // }
{ // else
return false; // {
} // return false;
} // }
//}
} }
private static async Task<string?> GetLinuxUserId() private static async Task<string?> GetLinuxUserId()
@@ -814,17 +889,32 @@ namespace ServiceLib.Common
public static async Task<string?> SetLinuxChmod(string? fileName) public static async Task<string?> SetLinuxChmod(string? fileName)
{ {
if (fileName.IsNullOrEmpty()) return null; if (fileName.IsNullOrEmpty()) return null;
if (fileName.Contains(' ')) fileName = fileName.AppendQuotes();
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
var arg = new List<string>() { "-c", $"chmod +x {fileName}" }; var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
return await GetCliWrapOutput("/bin/bash", arg); return await GetCliWrapOutput("/bin/bash", arg);
} }
public static async Task<string?> GetLinuxFontFamily(string lang) public static async Task<string?> GetLinuxFontFamily(string lang)
{ {
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" }; // var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
var arg = new List<string>() { "-c", $"fc-list : family" }; var arg = new List<string>() { "-c", $"fc-list : family" };
return await GetCliWrapOutput("/bin/bash", arg); return await GetCliWrapOutput("/bin/bash", arg);
} }
public static string? GetHomePath()
{
return IsWindows()
? Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%")
: Environment.GetEnvironmentVariable("HOME");
}
public static async Task<string?> GetListNetworkServices()
{
var arg = new List<string>() { "-c", $"networksetup -listallnetworkservices" };
return await GetCliWrapOutput("/bin/bash", arg);
}
#endregion Platform #endregion Platform
} }
} }

View File

@@ -0,0 +1,52 @@
using Microsoft.Win32;
namespace ServiceLib.Common
{
internal static class WindowsUtils
{
public static string? RegReadValue(string path, string name, string def)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.OpenSubKey(path, false);
var value = regKey?.GetValue(name) as string;
return Utils.IsNullOrEmpty(value) ? def : value;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
return def;
}
public static void RegWriteValue(string path, string name, object value)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.CreateSubKey(path);
if (Utils.IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
}
}

View File

@@ -4,14 +4,8 @@
{ {
v2fly = 1, v2fly = 1,
Xray = 2, Xray = 2,
//SagerNet = 3,
v2fly_v5 = 4, v2fly_v5 = 4,
//clash = 11,
//clash_meta = 12,
mihomo = 13, mihomo = 13,
hysteria = 21, hysteria = 21,
naiveproxy = 22, naiveproxy = 22,
tuic = 23, tuic = 23,

View File

@@ -3,12 +3,12 @@
public enum EInboundProtocol public enum EInboundProtocol
{ {
socks = 0, socks = 0,
http,
socks2, socks2,
http2, socks3,
pac, pac,
api, api,
api2, api2,
mixed,
speedtest = 21 speedtest = 21
} }
} }

View File

@@ -5,6 +5,8 @@
ClearMsg, ClearMsg,
SendMsgView, SendMsgView,
SendSnackMsg, SendSnackMsg,
RefreshProfiles RefreshProfiles,
StopSpeedtest,
AppExit
} }
} }

View File

@@ -4,5 +4,6 @@
{ {
Default = 0, Default = 0,
Russia = 1, Russia = 1,
Iran = 2,
} }
} }

View File

@@ -6,7 +6,7 @@
kcp, kcp,
ws, ws,
httpupgrade, httpupgrade,
splithttp, xhttp,
h2, h2,
http, http,
quic, quic,

View File

@@ -20,6 +20,7 @@
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases"; public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"; 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 SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
public const string IPAPIUrl = "https://api.ip.sb/geoip";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="; public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json"; public const string ConfigFileName = "guiNConfig.json";
@@ -28,21 +29,25 @@
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json"; public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json"; public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
public const string ClashMixinConfigFileName = "Mixin.yaml"; public const string ClashMixinConfigFileName = "Mixin.yaml";
public const string V2raySampleClient = "ServiceLib.Sample.SampleClientConfig";
public const string SingboxSampleClient = "ServiceLib.Sample.SingboxSampleClientConfig"; public const string NamespaceSample = "ServiceLib.Sample.";
public const string V2raySampleHttpRequestFileName = "ServiceLib.Sample.SampleHttpRequest"; public const string V2raySampleClient = NamespaceSample + "SampleClientConfig";
public const string V2raySampleHttpResponseFileName = "ServiceLib.Sample.SampleHttpResponse"; public const string SingboxSampleClient = NamespaceSample + "SingboxSampleClientConfig";
public const string V2raySampleInbound = "ServiceLib.Sample.SampleInbound"; public const string V2raySampleHttpRequestFileName = NamespaceSample + "SampleHttpRequest";
public const string V2raySampleOutbound = "ServiceLib.Sample.SampleOutbound"; public const string V2raySampleHttpResponseFileName = NamespaceSample + "SampleHttpResponse";
public const string SingboxSampleOutbound = "ServiceLib.Sample.SingboxSampleOutbound"; public const string V2raySampleInbound = NamespaceSample + "SampleInbound";
public const string CustomRoutingFileName = "ServiceLib.Sample.custom_routing_"; public const string V2raySampleOutbound = NamespaceSample + "SampleOutbound";
public const string TunSingboxDNSFileName = "ServiceLib.Sample.tun_singbox_dns"; public const string SingboxSampleOutbound = NamespaceSample + "SingboxSampleOutbound";
public const string TunSingboxInboundFileName = "ServiceLib.Sample.tun_singbox_inbound"; public const string CustomRoutingFileName = NamespaceSample + "custom_routing_";
public const string TunSingboxRulesFileName = "ServiceLib.Sample.tun_singbox_rules"; public const string TunSingboxDNSFileName = NamespaceSample + "tun_singbox_dns";
public const string DNSV2rayNormalFileName = "ServiceLib.Sample.dns_v2ray_normal"; public const string TunSingboxInboundFileName = NamespaceSample + "tun_singbox_inbound";
public const string DNSSingboxNormalFileName = "ServiceLib.Sample.dns_singbox_normal"; public const string TunSingboxRulesFileName = NamespaceSample + "tun_singbox_rules";
public const string ClashMixinYaml = "ServiceLib.Sample.clash_mixin_yaml"; public const string DNSV2rayNormalFileName = NamespaceSample + "dns_v2ray_normal";
public const string ClashTunYaml = "ServiceLib.Sample.clash_tun_yaml"; public const string DNSSingboxNormalFileName = NamespaceSample + "dns_singbox_normal";
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
public const string PacFileName = NamespaceSample + "pac";
public const string DefaultSecurity = "auto"; public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp"; public const string DefaultNetwork = "tcp";
@@ -63,15 +68,17 @@
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
public const string AutoRunName = "v2rayNAutoRun"; public const string AutoRunName = "v2rayNAutoRun";
public const string CustomIconName = "v2rayN.ico"; 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 SystemProxyExceptionsWindows = "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 SystemProxyExceptionsLinux = "localhost, 127.0.0.0/8, ::1";
public const string RoutingRuleComma = "<COMMA>"; public const string RoutingRuleComma = "<COMMA>";
public const string GrpcGunMode = "gun"; public const string GrpcGunMode = "gun";
public const string GrpcMultiMode = "multi"; public const string GrpcMultiMode = "multi";
public const int MaxPort = 65536; public const int MaxPort = 65536;
public const string DelayUnit = ""; public const string DelayUnit = "";
public const string SpeedUnit = ""; public const string SpeedUnit = "";
public const int MinFontSize = 10; public const int MinFontSize = 8;
public const string RebootAs = "rebootas"; public const string RebootAs = "rebootas";
public const string AvaAssets = "avares://v2rayN/Assets/";
public static readonly List<string> IEProxyProtocols = new() { public static readonly List<string> IEProxyProtocols = new() {
"{ip}:{http_port}", "{ip}:{http_port}",
@@ -102,9 +109,9 @@
public static readonly List<string> SpeedTestUrls = new() { public static readonly List<string> SpeedTestUrls = new() {
@"https://speed.cloudflare.com/__down?bytes=100000000", @"https://speed.cloudflare.com/__down?bytes=100000000",
@"https://speed.cloudflare.com/__down?bytes=50000000",
@"https://speed.cloudflare.com/__down?bytes=10000000", @"https://speed.cloudflare.com/__down?bytes=10000000",
@"http://cachefly.cachefly.net/50mb.test", @"https://cachefly.cachefly.net/50mb.test",
@"http://cachefly.cachefly.net/10mb.test"
}; };
public static readonly List<string> SpeedPingTestUrls = new() { public static readonly List<string> SpeedPingTestUrls = new() {
@@ -117,21 +124,25 @@
public static readonly List<string> GeoFilesSources = new() { public static readonly List<string> GeoFilesSources = new() {
"", "",
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat", @"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat",
}; };
public static readonly List<string> SingboxRulesetSources = new() { public static readonly List<string> SingboxRulesetSources = new() {
"", "",
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs", @"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs",
}; };
public static readonly List<string> RoutingRulesSources = new() { public static readonly List<string> RoutingRulesSources = new() {
"", "",
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json", @"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json",
}; };
public static readonly List<string> DNSTemplateSources = new() { public static readonly List<string> DNSTemplateSources = new() {
"", "",
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/", @"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/",
}; };
public static readonly Dictionary<string, string> UserAgentTexts = new() public static readonly Dictionary<string, string> UserAgentTexts = new()
@@ -172,29 +183,28 @@
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" }; 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> 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> 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> 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> 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> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "xhttp", "h2", "quic", "grpc" };
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" }; public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
public static readonly List<string> CoreTypes = new() { "v2fly", "Xray", "sing_box" }; public static readonly List<string> CoreTypes = new() { "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> 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> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" }; 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> 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> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
public static readonly List<string> XhttpMode = new() { "auto", "packet-up", "stream-up", "stream-one" };
public static readonly List<string> AllowInsecure = new() { "true", "false", "" }; 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> 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> 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> 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> 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> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru", "hu" };
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> 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> LogLevels = new() { "debug", "info", "warning", "error", "none" };
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" }; public static readonly List<string> InboundTags = new() { "socks", "socks2", "socks3" };
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" }; 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> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"]; public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
@@ -204,9 +214,9 @@
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" }; 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> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" }; public static readonly List<string> allowSelectType = new() { "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> notAllowTestType = new() { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" }; public static readonly List<string> proxyVehicleType = new() { "file", "http" };
#endregion const #endregion const
} }

View File

@@ -27,7 +27,7 @@
get get
{ {
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2)); _statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
return _statePort2.Value; return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
} }
} }
@@ -46,11 +46,18 @@
public bool InitApp() public bool InitApp()
{ {
_config = ConfigHandler.LoadConfig(); if (Utils.IsNonWindows() && Utils.HasWritePermission() == false)
if (_config == null) {
Environment.SetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA", "1", EnvironmentVariableTarget.Process);
}
Logging.Setup();
var config = ConfigHandler.LoadConfig();
if (config == null)
{ {
return false; return false;
} }
_config = config;
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage); Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
//Under Win10 //Under Win10
@@ -70,15 +77,20 @@
public bool InitComponents() public bool InitComponents()
{ {
Logging.Setup(); Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
Logging.LoggingEnabled(true); Logging.LoggingEnabled(_config.GuiItem.EnableLog);
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
Logging.ClearLogs(); Logging.ClearLogs();
return true; return true;
} }
public bool Reset()
{
_statePort = null;
_statePort2 = null;
return true;
}
#endregion Init #endregion Init
#region Config #region Config
@@ -211,12 +223,12 @@
public async Task<List<RoutingItem>?> RoutingItems() public async Task<List<RoutingItem>?> RoutingItems()
{ {
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(it => it.Locked == false).OrderBy(t => t.Sort).ToListAsync(); return await SQLiteHelper.Instance.TableAsync<RoutingItem>().OrderBy(t => t.Sort).ToListAsync();
} }
public async Task<RoutingItem?> GetRoutingItem(string id) public async Task<RoutingItem?> GetRoutingItem(string id)
{ {
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Locked == false && it.Id == id); return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Id == id);
} }
public async Task<List<DNSItem>?> DNSItems() public async Task<List<DNSItem>?> DNSItems()
@@ -247,7 +259,7 @@
case ECoreType.sing_box: case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox; return Global.SsSecuritiesInSingbox;
} }
return Global.SsSecuritiesInSagerNet; return Global.SsSecuritiesInSingbox;
} }
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType) public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
@@ -257,16 +269,8 @@
return (ECoreType)profileItem.CoreType; return (ECoreType)profileItem.CoreType;
} }
if (_config.CoreTypeItem == null) var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType);
{ return item?.CoreType ?? ECoreType.Xray;
return ECoreType.Xray;
}
var item = _config.CoreTypeItem.FirstOrDefault(it => it.ConfigType == eConfigType);
if (item == null)
{
return ECoreType.Xray;
}
return item.CoreType;
} }
#endregion Core Type #endregion Core Type

View File

@@ -0,0 +1,159 @@
using System.Security.Principal;
using System.Text.RegularExpressions;
namespace ServiceLib.Handler
{
public static class AutoStartupHandler
{
public static async Task<bool> UpdateTask(Config config)
{
if (Utils.IsWindows())
{
await ClearTaskWindows();
if (config.GuiItem.AutoRun)
{
await SetTaskWindows();
}
}
else if (Utils.IsLinux())
{
await ClearTaskLinux();
if (config.GuiItem.AutoRun)
{
await SetTaskLinux();
}
}
else if (Utils.IsOSX())
{
//TODO
}
return true;
}
#region Windows
private static async Task ClearTaskWindows()
{
var autoRunName = GetAutoRunNameWindows();
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, "");
if (Utils.IsAdministrator())
{
AutoStartTaskService(autoRunName, "", "");
}
}
private static async Task SetTaskWindows()
{
try
{
var autoRunName = GetAutoRunNameWindows();
var exePath = Utils.GetExePath();
if (Utils.IsAdministrator())
{
AutoStartTaskService(autoRunName, exePath, "");
}
else
{
WindowsUtils.RegWriteValue(Global.AutoRunRegPath, autoRunName, exePath.AppendQuotes());
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
/// <summary>
/// Auto Start via TaskService
/// </summary>
/// <param name="taskName"></param>
/// <param name="fileName"></param>
/// <param name="description"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void AutoStartTaskService(string taskName, string fileName, string description)
{
if (Utils.IsNullOrEmpty(taskName))
{
return;
}
var logonUser = WindowsIdentity.GetCurrent().Name;
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
if (Utils.IsNullOrEmpty(fileName))
{
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = description;
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
taskService.RootFolder.RegisterTaskDefinition(taskName, task);
}
private static string GetAutoRunNameWindows()
{
return $"{Global.AutoRunName}_{Utils.GetMd5(Utils.StartupPath())}";
}
#endregion Windows
#region Linux
private static async Task ClearTaskLinux()
{
try
{
File.Delete(GetHomePathLinux());
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
private static async Task SetTaskLinux()
{
try
{
var linuxConfig = Utils.GetEmbedText(Global.LinuxAutostartConfig);
if (linuxConfig.IsNotEmpty())
{
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
Logging.SaveLog(linuxConfig);
var homePath = GetHomePathLinux();
await File.WriteAllTextAsync(homePath, linuxConfig);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
private static string GetHomePathLinux()
{
var homePath = Path.Combine(Utils.GetHomePath(), ".config", "autostart", $"{Global.AppName}.desktop");
Directory.CreateDirectory(Path.GetDirectoryName(homePath));
return homePath;
}
#endregion Linux
}
}

View File

@@ -1,4 +1,4 @@
using System.Data; using System.Data;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace ServiceLib.Handler namespace ServiceLib.Handler
@@ -9,7 +9,6 @@ namespace ServiceLib.Handler
public class ConfigHandler public class ConfigHandler
{ {
private static readonly string _configRes = Global.ConfigFileName; private static readonly string _configRes = Global.ConfigFileName;
private static readonly object _objLock = new();
#region ConfigHandler #region ConfigHandler
@@ -62,17 +61,14 @@ namespace ServiceLib.Handler
{ {
if (config.Inbound.Count > 0) if (config.Inbound.Count > 0)
{ {
config.Inbound[0].Protocol = EInboundProtocol.socks.ToString(); config.Inbound.First().Protocol = EInboundProtocol.socks.ToString();
} }
} }
config.RoutingBasicItem ??= new()
{
EnableRoutingAdvanced = true
};
config.RoutingBasicItem ??= new();
if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy)) if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy))
{ {
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies[0];//"IPIfNonMatch"; config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();
} }
config.KcpItem ??= new KcpItem config.KcpItem ??= new KcpItem
@@ -113,7 +109,7 @@ namespace ServiceLib.Handler
{ {
if (Thread.CurrentThread.CurrentCulture.Name.Equals("zh-cn", StringComparison.CurrentCultureIgnoreCase)) if (Thread.CurrentThread.CurrentCulture.Name.Equals("zh-cn", StringComparison.CurrentCultureIgnoreCase))
{ {
config.UiItem.CurrentLanguage = Global.Languages[0]; config.UiItem.CurrentLanguage = Global.Languages.First();
} }
else else
{ {
@@ -122,10 +118,6 @@ namespace ServiceLib.Handler
} }
config.ConstItem ??= new ConstItem(); config.ConstItem ??= new ConstItem();
if (Utils.IsNullOrEmpty(config.ConstItem.DefIEProxyExceptions))
{
config.ConstItem.DefIEProxyExceptions = Global.IEProxyExceptions;
}
config.SpeedTestItem ??= new(); config.SpeedTestItem ??= new();
if (config.SpeedTestItem.SpeedTestTimeout < 10) if (config.SpeedTestItem.SpeedTestTimeout < 10)
@@ -134,7 +126,7 @@ namespace ServiceLib.Handler
} }
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedTestUrl)) if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedTestUrl))
{ {
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls[0]; config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls.First();
} }
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedPingTestUrl)) if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedPingTestUrl))
{ {
@@ -150,7 +142,7 @@ namespace ServiceLib.Handler
config.Mux4SboxItem ??= new() config.Mux4SboxItem ??= new()
{ {
Protocol = Global.SingboxMuxs[0], Protocol = Global.SingboxMuxs.First(),
MaxConnections = 8 MaxConnections = 8
}; };
@@ -162,6 +154,17 @@ namespace ServiceLib.Handler
config.ClashUIItem ??= new(); config.ClashUIItem ??= new();
config.SystemProxyItem ??= new(); config.SystemProxyItem ??= new();
config.WebDavItem ??= new(); config.WebDavItem ??= new();
config.CheckUpdateItem ??= new();
if (Utils.IsNotEmpty(config.ConstItem.DefIEProxyExceptions))
{
config.SystemProxyItem.SystemProxyExceptions = $"{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
config.ConstItem.DefIEProxyExceptions = string.Empty;
}
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
{
config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux;
}
return config; return config;
} }
@@ -173,30 +176,26 @@ namespace ServiceLib.Handler
/// <returns></returns> /// <returns></returns>
public static async Task<int> SaveConfig(Config config) public static async Task<int> SaveConfig(Config config)
{ {
lock (_objLock) try
{ {
try //save temp file
{ var resPath = Utils.GetConfigPath(_configRes);
//save temp file var tempPath = $"{resPath}_temp";
var resPath = Utils.GetConfigPath(_configRes);
var tempPath = $"{resPath}_temp";
if (JsonUtils.ToFile(config, tempPath) != 0)
{
return -1;
}
if (File.Exists(resPath)) var content = JsonUtils.Serialize(config, true, true);
{ if (content.IsNullOrEmpty())
File.Delete(resPath);
}
//rename
File.Move(tempPath, resPath);
}
catch (Exception ex)
{ {
Logging.SaveLog("ToJsonFile", ex);
return -1; return -1;
} }
await File.WriteAllTextAsync(tempPath, content);
//rename
File.Move(tempPath, resPath, true);
}
catch (Exception ex)
{
Logging.SaveLog("ToJsonFile", ex);
return -1;
} }
return 0; return 0;
@@ -239,6 +238,7 @@ namespace ServiceLib.Handler
item.PublicKey = profileItem.PublicKey; item.PublicKey = profileItem.PublicKey;
item.ShortId = profileItem.ShortId; item.ShortId = profileItem.ShortId;
item.SpiderX = profileItem.SpiderX; item.SpiderX = profileItem.SpiderX;
item.Extra = profileItem.Extra;
} }
var ret = item.ConfigType switch var ret = item.ConfigType switch
@@ -383,7 +383,7 @@ namespace ServiceLib.Handler
} }
var item = await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(t => t.Port > 0); var item = await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(t => t.Port > 0);
return await SetDefaultServerIndex(config, item.IndexId); return await SetDefaultServerIndex(config, item?.IndexId);
} }
public static async Task<ProfileItem?> GetDefaultServer(Config config) public static async Task<ProfileItem?> GetDefaultServer(Config config)
@@ -429,7 +429,7 @@ namespace ServiceLib.Handler
{ {
return 0; return 0;
} }
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].IndexId) - 1; sort = ProfileExHandler.Instance.GetSort(lstProfile.First().IndexId) - 1;
break; break;
} }
@@ -465,7 +465,7 @@ namespace ServiceLib.Handler
break; break;
} }
case EMove.Position: case EMove.Position:
sort = pos * 10 + 1; sort = (pos * 10) + 1;
break; break;
} }
@@ -766,69 +766,66 @@ namespace ServiceLib.Handler
}).ToList(); }).ToList();
Enum.TryParse(colName, true, out EServerColName name); Enum.TryParse(colName, true, out EServerColName name);
var propertyName = string.Empty;
switch (name)
{
case EServerColName.ConfigType:
case EServerColName.Remarks:
case EServerColName.Address:
case EServerColName.Port:
case EServerColName.Network:
case EServerColName.StreamSecurity:
propertyName = name.ToString();
break;
case EServerColName.DelayVal:
propertyName = "Delay";
break;
case EServerColName.SpeedVal:
propertyName = "Speed";
break;
case EServerColName.SubRemarks:
propertyName = "Subid";
break;
default:
return -1;
}
var items = lstProfile.AsQueryable();
if (asc) if (asc)
{ {
lstProfile = items.OrderBy(propertyName).ToList(); lstProfile = name switch
{
EServerColName.ConfigType => lstProfile.OrderBy(t => t.ConfigType).ToList(),
EServerColName.Remarks => lstProfile.OrderBy(t => t.Remarks).ToList(),
EServerColName.Address => lstProfile.OrderBy(t => t.Address).ToList(),
EServerColName.Port => lstProfile.OrderBy(t => t.Port).ToList(),
EServerColName.Network => lstProfile.OrderBy(t => t.Network).ToList(),
EServerColName.StreamSecurity => lstProfile.OrderBy(t => t.StreamSecurity).ToList(),
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
_ => lstProfile
};
} }
else else
{ {
lstProfile = items.OrderByDescending(propertyName).ToList(); lstProfile = name switch
{
EServerColName.ConfigType => lstProfile.OrderByDescending(t => t.ConfigType).ToList(),
EServerColName.Remarks => lstProfile.OrderByDescending(t => t.Remarks).ToList(),
EServerColName.Address => lstProfile.OrderByDescending(t => t.Address).ToList(),
EServerColName.Port => lstProfile.OrderByDescending(t => t.Port).ToList(),
EServerColName.Network => lstProfile.OrderByDescending(t => t.Network).ToList(),
EServerColName.StreamSecurity => lstProfile.OrderByDescending(t => t.StreamSecurity).ToList(),
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
_ => lstProfile
};
} }
for (int i = 0; i < lstProfile.Count; i++)
for (var i = 0; i < lstProfile.Count; i++)
{ {
ProfileExHandler.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10); ProfileExHandler.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10);
} }
if (name == EServerColName.DelayVal) switch (name)
{ {
var maxSort = lstProfile.Max(t => t.Sort) + 10; case EServerColName.DelayVal:
foreach (var item in lstProfile)
{
if (item.Delay <= 0)
{ {
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort); var maxSort = lstProfile.Max(t => t.Sort) + 10;
foreach (var item in lstProfile.Where(item => item.Delay <= 0))
{
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
}
break;
} }
} case EServerColName.SpeedVal:
}
if (name == EServerColName.SpeedVal)
{
var maxSort = lstProfile.Max(t => t.Sort) + 10;
foreach (var item in lstProfile)
{
if (item.Speed <= 0)
{ {
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort); var maxSort = lstProfile.Max(t => t.Sort) + 10;
foreach (var item in lstProfile.Where(item => item.Speed <= 0))
{
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
}
break;
} }
}
} }
return 0; return 0;
@@ -957,7 +954,6 @@ namespace ServiceLib.Handler
&& o.Address == n.Address && o.Address == n.Address
&& o.Port == n.Port && o.Port == n.Port
&& o.Id == n.Id && o.Id == n.Id
&& o.AlterId == n.AlterId
&& o.Security == n.Security && o.Security == n.Security
&& o.Network == n.Network && o.Network == n.Network
&& o.HeaderType == n.HeaderType && o.HeaderType == n.HeaderType
@@ -966,6 +962,10 @@ namespace ServiceLib.Handler
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity) && (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& o.Flow == n.Flow && o.Flow == n.Flow
&& o.Sni == n.Sni && o.Sni == n.Sni
&& o.Alpn == n.Alpn
&& o.Fingerprint == n.Fingerprint
&& o.PublicKey == n.PublicKey
&& o.ShortId == n.ShortId
&& (!remarks || o.Remarks == n.Remarks); && (!remarks || o.Remarks == n.Remarks);
} }
@@ -1023,6 +1023,35 @@ namespace ServiceLib.Handler
return result; return result;
} }
public static async Task<ProfileItem?> GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
{
ProfileItem? itemSocks = null;
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
{
itemSocks = new ProfileItem()
{
CoreType = ECoreType.sing_box,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Sni = node.Address, //Tun2SocksAddress
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
};
}
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
{
var preCoreType = config.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
itemSocks = new ProfileItem()
{
CoreType = preCoreType,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Port = node.PreSocksPort.Value,
};
}
return itemSocks;
}
#endregion Server #endregion Server
#region Batch add servers #region Batch add servers
@@ -1034,14 +1063,14 @@ namespace ServiceLib.Handler
/// <param name="strData"></param> /// <param name="strData"></param>
/// <param name="subid"></param> /// <param name="subid"></param>
/// <returns>成功导入的数量</returns> /// <returns>成功导入的数量</returns>
private static async Task<int> AddBatchServers(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub) private static async Task<int> AddBatchServersCommon(Config config, string strData, string subid, bool isSub)
{ {
if (Utils.IsNullOrEmpty(strData)) if (Utils.IsNullOrEmpty(strData))
{ {
return -1; return -1;
} }
string subFilter = string.Empty; var subFilter = string.Empty;
//remove sub items //remove sub items
if (isSub && Utils.IsNotEmpty(subid)) if (isSub && Utils.IsNotEmpty(subid))
{ {
@@ -1049,16 +1078,14 @@ namespace ServiceLib.Handler
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? ""; subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
} }
int countServers = 0; var countServers = 0;
//Check for duplicate indexId
List<string>? lstDbIndexId = null;
List<ProfileItem> lstAdd = new(); List<ProfileItem> lstAdd = new();
var arrData = strData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty()); var arrData = strData.Split(Environment.NewLine.ToCharArray()).Where(t => !t.IsNullOrEmpty());
if (isSub) if (isSub)
{ {
arrData = arrData.Distinct(); arrData = arrData.Distinct();
} }
foreach (string str in arrData) foreach (var str in arrData)
{ {
//maybe sub //maybe sub
if (!isSub && (str.StartsWith(Global.HttpsProtocol) || str.StartsWith(Global.HttpProtocol))) if (!isSub && (str.StartsWith(Global.HttpsProtocol) || str.StartsWith(Global.HttpProtocol)))
@@ -1075,35 +1102,12 @@ namespace ServiceLib.Handler
continue; continue;
} }
//exist sub items //exist sub items //filter
if (isSub && Utils.IsNotEmpty(subid)) if (isSub && Utils.IsNotEmpty(subid) && Utils.IsNotEmpty(subFilter))
{ {
var existItem = lstOriSub?.FirstOrDefault(t => t.IsSub == isSub if (!Regex.IsMatch(profileItem.Remarks, subFilter))
&& config.UiItem.EnableUpdateSubOnlyRemarksExist ? t.Remarks == profileItem.Remarks : CompareProfileItem(t, profileItem, true));
if (existItem != null)
{ {
//Check for duplicate indexId continue;
if (lstDbIndexId is null)
{
lstDbIndexId = await AppHandler.Instance.ProfileItemIndexes("");
}
if (lstAdd.Any(t => t.IndexId == existItem.IndexId)
|| lstDbIndexId.Any(t => t == existItem.IndexId))
{
profileItem.IndexId = string.Empty;
}
else
{
profileItem.IndexId = existItem.IndexId;
}
}
//filter
if (Utils.IsNotEmpty(subFilter))
{
if (!Regex.IsMatch(profileItem.Remarks, subFilter))
{
continue;
}
} }
} }
profileItem.Subid = subid; profileItem.Subid = subid;
@@ -1138,7 +1142,7 @@ namespace ServiceLib.Handler
return countServers; return countServers;
} }
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub) private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub)
{ {
if (Utils.IsNullOrEmpty(strData)) if (Utils.IsNullOrEmpty(strData))
{ {
@@ -1222,10 +1226,7 @@ namespace ServiceLib.Handler
{ {
await RemoveServerViaSubid(config, subid, isSub); await RemoveServerViaSubid(config, subid, isSub);
} }
if (isSub && lstOriSub?.Count == 1)
{
profileItem.IndexId = lstOriSub[0].IndexId;
}
profileItem.Subid = subid; profileItem.Subid = subid;
profileItem.IsSub = isSub; profileItem.IsSub = isSub;
profileItem.PreSocksPort = preSocksPort; profileItem.PreSocksPort = preSocksPort;
@@ -1239,7 +1240,7 @@ namespace ServiceLib.Handler
} }
} }
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub, List<ProfileItem> lstOriSub) private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub)
{ {
if (Utils.IsNullOrEmpty(strData)) if (Utils.IsNullOrEmpty(strData))
{ {
@@ -1278,34 +1279,61 @@ namespace ServiceLib.Handler
return -1; return -1;
} }
List<ProfileItem>? lstOriSub = null; List<ProfileItem>? lstOriSub = null;
ProfileItem? activeProfile = null;
if (isSub && Utils.IsNotEmpty(subid)) if (isSub && Utils.IsNotEmpty(subid))
{ {
lstOriSub = await AppHandler.Instance.ProfileItems(subid); lstOriSub = await AppHandler.Instance.ProfileItems(subid);
activeProfile = lstOriSub?.FirstOrDefault(t => t.IndexId == config.IndexId);
} }
var counter = 0; var counter = 0;
if (Utils.IsBase64String(strData)) if (Utils.IsBase64String(strData))
{ {
counter = await AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub); counter = await AddBatchServersCommon(config, Utils.Base64Decode(strData), subid, isSub);
} }
if (counter < 1) if (counter < 1)
{ {
counter = await AddBatchServers(config, strData, subid, isSub, lstOriSub); counter = await AddBatchServersCommon(config, strData, subid, isSub);
} }
if (counter < 1) if (counter < 1)
{ {
counter = await AddBatchServers(config, Utils.Base64Decode(strData), subid, isSub, lstOriSub); counter = await AddBatchServersCommon(config, Utils.Base64Decode(strData), subid, isSub);
} }
if (counter < 1) if (counter < 1)
{ {
counter = await AddBatchServers4SsSIP008(config, strData, subid, isSub, lstOriSub); counter = await AddBatchServers4SsSIP008(config, strData, subid, isSub);
} }
//maybe other sub //maybe other sub
if (counter < 1) if (counter < 1)
{ {
counter = await AddBatchServers4Custom(config, strData, subid, isSub, lstOriSub); counter = await AddBatchServers4Custom(config, strData, subid, isSub);
}
//Select active node
if (activeProfile != null)
{
var lstSub = await AppHandler.Instance.ProfileItems(subid);
var existItem = lstSub?.FirstOrDefault(t => config.UiItem.EnableUpdateSubOnlyRemarksExist ? t.Remarks == activeProfile.Remarks : CompareProfileItem(t, activeProfile, true));
if (existItem != null)
{
await ConfigHandler.SetDefaultServerIndex(config, existItem.IndexId);
}
}
//Keep the last traffic statistics
if (lstOriSub != null)
{
var lstSub = await AppHandler.Instance.ProfileItems(subid);
foreach (var item in lstSub)
{
var existItem = lstOriSub?.FirstOrDefault(t => config.UiItem.EnableUpdateSubOnlyRemarksExist ? t.Remarks == item.Remarks : CompareProfileItem(t, item, true));
if (existItem != null)
{
await StatisticsHandler.Instance.CloneServerStatItem(existItem.IndexId, item.IndexId);
}
}
} }
return counter; return counter;
@@ -1373,6 +1401,7 @@ namespace ServiceLib.Handler
item.PrevProfile = subItem.PrevProfile; item.PrevProfile = subItem.PrevProfile;
item.NextProfile = subItem.NextProfile; item.NextProfile = subItem.NextProfile;
item.PreSocksPort = subItem.PreSocksPort; item.PreSocksPort = subItem.PreSocksPort;
item.Memo = subItem.Memo;
} }
if (Utils.IsNullOrEmpty(item.Id)) if (Utils.IsNullOrEmpty(item.Id))
@@ -1609,7 +1638,7 @@ namespace ServiceLib.Handler
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId); var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
if (item is null) if (item is null)
{ {
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(t => t.Locked == false); var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
await SetDefaultRouting(config, item2); await SetDefaultRouting(config, item2);
return item2; return item2;
} }
@@ -1683,6 +1712,15 @@ namespace ServiceLib.Handler
{ {
var ver = "V3-"; var ver = "V3-";
var items = await AppHandler.Instance.RoutingItems(); var items = await AppHandler.Instance.RoutingItems();
//TODO Temporary code to be removed later
var lockItem = items?.FirstOrDefault(t => t.Locked == true);
if (lockItem != null)
{
await ConfigHandler.RemoveRoutingItem(lockItem);
items = await AppHandler.Instance.RoutingItems();
}
if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0) if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0)
{ {
return 0; return 0;
@@ -1723,11 +1761,6 @@ namespace ServiceLib.Handler
return 0; return 0;
} }
public static async Task<RoutingItem?> GetLockedRoutingItem(Config config)
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Locked == true);
}
public static async Task RemoveRoutingItem(RoutingItem routingItem) public static async Task RemoveRoutingItem(RoutingItem routingItem)
{ {
await SQLiteHelper.Instance.DeleteAsync(routingItem); await SQLiteHelper.Instance.DeleteAsync(routingItem);
@@ -1835,6 +1868,16 @@ namespace ServiceLib.Handler
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json")); await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json"));
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json")); await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
return true;
case EPresetType.Iran:
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[2];
config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[2];
config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[2];
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json"));
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json"));
return true; return true;
} }

View File

@@ -13,6 +13,7 @@ namespace ServiceLib.Handler
private Config _config; private Config _config;
private Process? _process; private Process? _process;
private Process? _processPre; private Process? _processPre;
private int _linuxSudoPid = -1;
private Action<bool, string>? _updateFunc; private Action<bool, string>? _updateFunc;
public async Task Init(Config config, Action<bool, string> updateFunc) public async Task Init(Config config, Action<bool, string> updateFunc)
@@ -23,7 +24,7 @@ namespace ServiceLib.Handler
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
if (Utils.IsLinux()) if (Utils.IsNonWindows())
{ {
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo) foreach (var it in coreInfo)
@@ -59,90 +60,56 @@ namespace ServiceLib.Handler
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName); var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName); var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
ShowMsg(false, result.Msg);
if (result.Success != true) if (result.Success != true)
{ {
ShowMsg(true, result.Msg);
return; return;
} }
else
{
ShowMsg(true, $"{node.GetSummary()}");
await CoreStop();
await CoreStart(node);
//In tun mode, do a delay check and restart the core ShowMsg(true, $"{node.GetSummary()}");
//if (_config.tunModeItem.enableTun) ShowMsg(false, $"{Utils.GetRuntimeInfo()}");
//{ ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
// Observable.Range(1, 1) await CoreStop();
// .Delay(TimeSpan.FromSeconds(15)) await Task.Delay(100);
// .Subscribe(x => await CoreStart(node);
// { await CoreStartPreService(node);
// {
// if (_process == null || _process.HasExited)
// {
// CoreStart(node);
// ShowMsg(false, "Tun mode restart the core once");
// Logging.SaveLog("Tun mode restart the core once");
// }
// }
// });
//}
}
} }
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds) public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
{ {
var pid = -1;
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray; var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName); var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType); var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
ShowMsg(false, result.Msg); ShowMsg(false, result.Msg);
if (result.Success) if (result.Success != true)
{ {
pid = await CoreStartSpeedtest(configPath, coreType); return -1;
} }
return pid;
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
return await CoreStartSpeedtest(configPath, coreType);
} }
public async Task CoreStop() public async Task CoreStop()
{ {
try try
{ {
bool hasProc = false;
if (_process != null) if (_process != null)
{ {
await KillProcess(_process); _process = await KillProcess(_process);
_process.Dispose();
_process = null;
hasProc = true;
} }
if (_processPre != null) if (_processPre != null)
{ {
await KillProcess(_processPre); _processPre = await KillProcess(_processPre);
_processPre.Dispose();
_processPre = null;
hasProc = true;
} }
if (!hasProc) if (_linuxSudoPid > 0)
{ {
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(); await KillProcessAsLinuxSudo();
foreach (var it in coreInfo)
{
if (it.CoreType == ECoreType.v2rayN)
{
continue;
}
foreach (var name in it.CoreExes)
{
var path = Utils.GetBinPath(Utils.GetExeName(name), it.CoreType.ToString());
var existing = Process.GetProcessesByName(name);
var pp = existing.FirstOrDefault(p => p.MainModule?.FileName != null && p.MainModule?.FileName.Contains(path) == true);
await KillProcess(pp);
}
}
} }
_linuxSudoPid = -1;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -154,8 +121,7 @@ namespace ServiceLib.Handler
{ {
try try
{ {
var _p = Process.GetProcessById(pid); await KillProcess(Process.GetProcessById(pid));
await KillProcess(_p);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -167,7 +133,7 @@ namespace ServiceLib.Handler
private string CoreFindExe(CoreInfo coreInfo) private string CoreFindExe(CoreInfo coreInfo)
{ {
string fileName = string.Empty; var fileName = string.Empty;
foreach (var name in coreInfo.CoreExes) foreach (var name in coreInfo.CoreExes)
{ {
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString()); var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
@@ -179,7 +145,7 @@ namespace ServiceLib.Handler
} }
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url); var msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
Logging.SaveLog(msg); Logging.SaveLog(msg);
ShowMsg(false, msg); ShowMsg(false, msg);
} }
@@ -188,70 +154,38 @@ namespace ServiceLib.Handler
private async Task CoreStart(ProfileItem node) private async Task CoreStart(ProfileItem node)
{ {
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}"); var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
//ECoreType coreType;
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
//{
// coreType = ECoreType.sing_box;
//}
//else
//{
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
//}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
_config.RunningCoreType = coreType;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(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 = await RunProcess(node, coreInfo, "", displayLog); var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
if (proc is null) if (proc is null)
{ {
return; return;
} }
_process = proc; _process = proc;
}
//start a pre service private async Task CoreStartPreService(ProfileItem node)
{
if (_process != null && !_process.HasExited) if (_process != null && !_process.HasExited)
{ {
ProfileItem? itemSocks = null; var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var preCoreType = ECoreType.sing_box; var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.TunModeItem.EnableTun)
{
itemSocks = new ProfileItem()
{
CoreType = preCoreType,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Sni = node.Address, //Tun2SocksAddress
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
};
}
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) if (itemSocks != null)
{ {
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName); var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2); var fileName = Utils.GetConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
if (result.Success) if (result.Success)
{ {
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = await RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true); var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
if (proc2 is not null) if (proc is null)
{ {
_processPre = proc2; return;
} }
_processPre = proc;
} }
} }
} }
@@ -259,13 +193,10 @@ namespace ServiceLib.Handler
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType) private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
{ {
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try try
{ {
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true); var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
if (proc is null) if (proc is null)
{ {
return -1; return -1;
@@ -276,8 +207,7 @@ namespace ServiceLib.Handler
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
string msg = ex.Message; ShowMsg(false, ex.Message);
ShowMsg(false, msg);
return -1; return -1;
} }
} }
@@ -287,19 +217,29 @@ namespace ServiceLib.Handler
_updateFunc?.Invoke(notify, msg); _updateFunc?.Invoke(notify, msg);
} }
private bool IsNeedSudo(ECoreType eCoreType)
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& (Utils.IsNonWindows())
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
#endregion Private #endregion Private
#region Process #region Process
private async Task<Process?> RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog) private async Task<Process?> RunProcess(CoreInfo coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
{ {
var fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
try try
{ {
string fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
Process proc = new() Process proc = new()
{ {
StartInfo = new() StartInfo = new()
@@ -315,33 +255,45 @@ namespace ServiceLib.Handler
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null, StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
} }
}; };
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
}
var startUpErrorMessage = new StringBuilder(); var startUpErrorMessage = new StringBuilder();
var startUpSuccessful = false; var startUpSuccessful = false;
if (displayLog) if (displayLog)
{ {
proc.OutputDataReceived += (sender, e) => proc.OutputDataReceived += (sender, e) =>
{ {
if (Utils.IsNotEmpty(e.Data)) if (Utils.IsNullOrEmpty(e.Data)) return;
{ ShowMsg(false, e.Data + Environment.NewLine);
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
}
}; };
proc.ErrorDataReceived += (sender, e) => proc.ErrorDataReceived += (sender, e) =>
{ {
if (Utils.IsNotEmpty(e.Data)) if (Utils.IsNullOrEmpty(e.Data)) return;
{ ShowMsg(false, e.Data + Environment.NewLine);
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
if (!startUpSuccessful) if (!startUpSuccessful)
{ {
startUpErrorMessage.Append(msg); startUpErrorMessage.Append(e.Data + Environment.NewLine);
}
} }
}; };
} }
proc.Start(); proc.Start();
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
if (isNeedSudo) _linuxSudoPid = proc.Id;
if (displayLog) if (displayLog)
{ {
proc.BeginOutputReadLine(); proc.BeginOutputReadLine();
@@ -364,34 +316,109 @@ namespace ServiceLib.Handler
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
string msg = ex.Message; ShowMsg(true, ex.Message);
ShowMsg(true, msg);
return null; return null;
} }
} }
private async Task KillProcess(Process? proc) private async Task<Process?> KillProcess(Process? proc)
{ {
if (proc is null) if (proc is null)
{ {
return; return null;
}
try
{
proc.Kill();
proc.WaitForExit(100);
if (!proc.HasExited)
{
proc.Kill();
proc.WaitForExit(100);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
} }
try { proc?.Kill(true); } catch { }
try { proc?.Close(); } catch { }
try { proc?.Dispose(); } catch { }
await Task.Delay(100);
return null;
} }
#endregion Process #endregion Process
#region Linux
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
{
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
proc.StartInfo.FileName = shFilePath;
proc.StartInfo.Arguments = "";
proc.StartInfo.WorkingDirectory = "";
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
}
}
private async Task KillProcessAsLinuxSudo()
{
var cmdLine = $"kill {_linuxSudoPid}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
Process proc = new()
{
StartInfo = new()
{
FileName = shFilePath,
UseShellExecute = false,
CreateNoWindow = true,
StandardInputEncoding = Encoding.UTF8,
RedirectStandardInput = true
}
};
proc.Start();
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
try
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
catch (Exception)
{
// ignored
}
}
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await proc.WaitForExitAsync(timeout.Token);
await Task.Delay(3000);
}
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
{
//Shell scripts
var shFilePath = Utils.GetBinPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
if (AppHandler.Instance.IsAdministrator)
{
sb.AppendLine($"{cmdLine}");
}
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
{
sb.AppendLine($"pkexec {cmdLine}");
}
else
{
sb.AppendLine($"sudo -S {cmdLine}");
}
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
Logging.SaveLog(shFilePath);
return shFilePath;
}
#endregion Linux
} }
} }

View File

@@ -1,6 +1,4 @@
using System.Runtime.Intrinsics.X86; namespace ServiceLib.Handler
namespace ServiceLib.Handler
{ {
public sealed class CoreInfoHandler public sealed class CoreInfoHandler
{ {
@@ -44,6 +42,8 @@ namespace ServiceLib.Handler
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip", DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip", DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip", DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
DownloadUrlOSX64 = Global.NUrl + "/download/{0}/v2rayN-macos-64.zip",
DownloadUrlOSXArm64 = Global.NUrl + "/download/{0}/v2rayN-macos-arm64.zip",
}); });
_coreInfo.Add(new CoreInfo _coreInfo.Add(new CoreInfo
@@ -74,13 +74,15 @@ namespace ServiceLib.Handler
{ {
CoreType = ECoreType.Xray, CoreType = ECoreType.Xray,
CoreExes = new List<string> { "xray", "wxray" }, CoreExes = new List<string> { "xray", "wxray" },
Arguments = "run {0}", Arguments = "run -c {0}",
Url = Global.XrayCoreUrl, Url = Global.XrayCoreUrl,
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip", DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip", DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip", DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip", DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
DownloadUrlOSX64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-64.zip",
DownloadUrlOSXArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-arm64-v8a.zip",
Match = "Xray", Match = "Xray",
VersionArg = "-version", VersionArg = "-version",
RedirectInfo = true, RedirectInfo = true,
@@ -89,7 +91,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo _coreInfo.Add(new CoreInfo
{ {
CoreType = ECoreType.mihomo, 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" }, CoreExes = new List<string> { "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash" },
Arguments = "-f config.json" + PortableMode(), Arguments = "-f config.json" + PortableMode(),
Url = Global.MihomoCoreUrl, Url = Global.MihomoCoreUrl,
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -97,6 +99,8 @@ namespace ServiceLib.Handler
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip", DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz", DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz", DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
DownloadUrlOSX64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz",
DownloadUrlOSXArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-arm64-{0}.gz",
Match = "Mihomo", Match = "Mihomo",
VersionArg = "-v", VersionArg = "-v",
RedirectInfo = true, RedirectInfo = true,
@@ -105,7 +109,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo _coreInfo.Add(new CoreInfo
{ {
CoreType = ECoreType.hysteria, CoreType = ECoreType.hysteria,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria" },
Arguments = "", Arguments = "",
Url = Global.HysteriaCoreUrl, Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -134,7 +138,7 @@ namespace ServiceLib.Handler
{ {
CoreType = ECoreType.sing_box, CoreType = ECoreType.sing_box,
CoreExes = new List<string> { "sing-box-client", "sing-box" }, CoreExes = new List<string> { "sing-box-client", "sing-box" },
Arguments = "run {0} --disable-color", Arguments = "run -c {0} --disable-color",
Url = Global.SingboxCoreUrl, Url = Global.SingboxCoreUrl,
RedirectInfo = true, RedirectInfo = true,
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -142,6 +146,8 @@ namespace ServiceLib.Handler
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip", DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz", DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz", DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
DownloadUrlOSX64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz",
DownloadUrlOSXArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz",
Match = "sing-box", Match = "sing-box",
VersionArg = "version", VersionArg = "version",
}); });
@@ -157,7 +163,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo _coreInfo.Add(new CoreInfo
{ {
CoreType = ECoreType.hysteria2, CoreType = ECoreType.hysteria2,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria" },
Arguments = "", Arguments = "",
Url = Global.HysteriaCoreUrl, Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -167,7 +173,7 @@ namespace ServiceLib.Handler
private string PortableMode() private string PortableMode()
{ {
return $" -d \"{Utils.GetBinPath("")}\""; return $" -d {Utils.GetBinPath("").AppendQuotes()}";
} }
} }
} }

View File

@@ -83,7 +83,6 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws): case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
if (Utils.IsNotEmpty(item.RequestHost)) if (Utils.IsNotEmpty(item.RequestHost))
{ {
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost)); dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
@@ -94,6 +93,25 @@ namespace ServiceLib.Handler.Fmt
} }
break; break;
case nameof(ETransport.xhttp):
if (Utils.IsNotEmpty(item.RequestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (Utils.IsNotEmpty(item.Path))
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
if (Utils.IsNotEmpty(item.HeaderType) && Global.XhttpMode.Contains(item.HeaderType))
{
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
}
if (Utils.IsNotEmpty(item.Extra))
{
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
}
break;
case nameof(ETransport.http): case nameof(ETransport.http):
case nameof(ETransport.h2): case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http); dicQuery["type"] = nameof(ETransport.http);
@@ -156,11 +174,17 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws): case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? ""); item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/"); item.Path = Utils.UrlDecode(query["path"] ?? "/");
break; break;
case nameof(ETransport.xhttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? "");
item.Extra = Utils.UrlDecode(query["extra"] ?? "");
break;
case nameof(ETransport.http): case nameof(ETransport.http):
case nameof(ETransport.h2): case nameof(ETransport.h2):
item.Network = nameof(ETransport.h2); item.Network = nameof(ETransport.h2);

View File

@@ -99,8 +99,8 @@ namespace ServiceLib.Handler.Fmt
{ {
return null; return null;
} }
item.Security = userInfoParts[0]; item.Security = userInfoParts.First();
item.Id = Utils.UrlDecode(userInfoParts[1]); item.Id = Utils.UrlDecode(userInfoParts.Last());
} }
else else
{ {
@@ -111,8 +111,8 @@ namespace ServiceLib.Handler.Fmt
{ {
return null; return null;
} }
item.Security = userInfoParts[0]; item.Security = userInfoParts.First();
item.Id = userInfoParts[1]; item.Id = userInfoParts.Last();
} }
var queryParameters = Utils.ParseQueryString(parsedUrl.Query); var queryParameters = Utils.ParseQueryString(parsedUrl.Query);

View File

@@ -5,9 +5,8 @@
public static ProfileItem? Resolve(string str, out string msg) public static ProfileItem? Resolve(string str, out string msg)
{ {
msg = ResUI.ConfigurationFormatIncorrect; msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
item = ResolveSocksNew(str) ?? ResolveSocks(str); var item = ResolveSocksNew(str) ?? ResolveSocks(str);
if (item == null) if (item == null)
{ {
return null; return null;
@@ -25,19 +24,13 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null) return null;
string url = string.Empty; var url = string.Empty;
string remark = string.Empty; var remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks)) if (Utils.IsNotEmpty(item.Remarks))
{ {
remark = "#" + Utils.UrlEncode(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 //new
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}"); var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark); return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
@@ -51,7 +44,7 @@
}; };
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..]; result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
//remark //remark
int indexRemark = result.IndexOf("#"); var indexRemark = result.IndexOf("#");
if (indexRemark > 0) if (indexRemark > 0)
{ {
try try
@@ -62,7 +55,7 @@
result = result[..indexRemark]; result = result[..indexRemark];
} }
//part decode //part decode
int indexS = result.IndexOf("@"); var indexS = result.IndexOf("@");
if (indexS > 0) if (indexS > 0)
{ {
} }
@@ -71,21 +64,20 @@
result = Utils.Base64Decode(result); result = Utils.Base64Decode(result);
} }
string[] arr1 = result.Split('@'); var arr1 = result.Split('@');
if (arr1.Length != 2) if (arr1.Length != 2)
{ {
return null; return null;
} }
string[] arr21 = arr1[0].Split(':'); var arr21 = arr1.First().Split(':');
//string[] arr22 = arr1[1].Split(':'); var indexPort = arr1.Last().LastIndexOf(":");
int indexPort = arr1[1].LastIndexOf(":");
if (arr21.Length != 2 || indexPort < 0) if (arr21.Length != 2 || indexPort < 0)
{ {
return null; return null;
} }
item.Address = arr1[1][..indexPort]; item.Address = arr1[1][..indexPort];
item.Port = Utils.ToInt(arr1[1][(indexPort + 1)..]); item.Port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
item.Security = arr21[0]; item.Security = arr21.First();
item.Id = arr21[1]; item.Id = arr21[1];
return item; return item;
@@ -106,10 +98,10 @@
// parse base64 UserInfo // parse base64 UserInfo
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
var userInfo = Utils.Base64Decode(rawUserInfo); var userInfo = Utils.Base64Decode(rawUserInfo);
var userInfoParts = userInfo.Split(new[] { ':' }, 2); var userInfoParts = userInfo.Split([':'], 2);
if (userInfoParts.Length == 2) if (userInfoParts.Length == 2)
{ {
item.Security = userInfoParts[0]; item.Security = userInfoParts.First();
item.Id = userInfoParts[1]; item.Id = userInfoParts[1];
} }

View File

@@ -21,8 +21,8 @@
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2) if (userInfoParts.Length == 2)
{ {
item.Id = userInfoParts[0]; item.Id = userInfoParts.First();
item.Security = userInfoParts[1]; item.Security = userInfoParts.Last();
} }
var query = Utils.ParseQueryString(url.Query); var query = Utils.ParseQueryString(url.Query);

View File

@@ -0,0 +1,105 @@
using System.Net.Sockets;
using System.Text;
namespace ServiceLib.Handler
{
public class PacHandler
{
private static string _configPath;
private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static byte[] _writeContent;
private static bool _isRunning;
private static bool _needRestart = true;
public static async Task Start(string configPath, int httpPort, int pacPort)
{
_needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
_configPath = configPath;
_httpPort = httpPort;
_pacPort = pacPort;
await InitText();
if (_needRestart)
{
Stop();
RunListener();
}
}
private static async Task InitText()
{
var path = Path.Combine(_configPath, "pac.txt");
if (!File.Exists(path))
{
var pac = Utils.GetEmbedText(Global.PacFileName);
await File.AppendAllTextAsync(path, pac);
}
var pacText =
(await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
sb.AppendLine();
sb.Append(pacText);
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
}
private static void RunListener()
{
_tcpListener = TcpListener.Create(_pacPort);
_isRunning = true;
_tcpListener.Start();
Task.Factory.StartNew(async () =>
{
while (_isRunning)
{
try
{
if (!_tcpListener.Pending())
{
await Task.Delay(10);
continue;
}
var client = await _tcpListener.AcceptTcpClientAsync();
await Task.Run(() => { WriteContent(client); });
}
catch
{
// ignored
}
}
}, TaskCreationOptions.LongRunning);
}
private static void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
public static void Stop()
{
if (_tcpListener == null) return;
try
{
_isRunning = false;
_tcpListener.Stop();
_tcpListener = null;
}
catch
{
// ignored
}
}
}
}

View File

@@ -9,7 +9,8 @@
private ServerStatItem? _serverStatItem; private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat; private List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc; private Action<ServerSpeedItem>? _updateFunc;
private StatisticsV2rayService? _statisticsV2Ray;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox; private StatisticsSingboxService? _statisticsSingbox;
public List<ServerStatItem> ServerStat => _lstServerStat; public List<ServerStatItem> ServerStat => _lstServerStat;
@@ -25,7 +26,7 @@
await InitData(); await InitData();
_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler); _statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler); _statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
} }
@@ -33,7 +34,7 @@
{ {
try try
{ {
_statisticsV2Ray?.Close(); _statisticsXray?.Close();
_statisticsSingbox?.Close(); _statisticsSingbox?.Close();
} }
catch (Exception ex) catch (Exception ex)
@@ -64,6 +65,25 @@
} }
} }
public async Task CloneServerStatItem(string indexId, string toIndexId)
{
if (_lstServerStat == null)
{
return;
}
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
if (stat == null)
{
return;
}
var toStat = JsonUtils.DeepCopy(stat);
toStat.IndexId = toIndexId;
await SQLiteHelper.Instance.ReplaceAsync(toStat);
_lstServerStat.Add(toStat);
}
private async Task InitData() private async Task InitData()
{ {
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )"); await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");

View File

@@ -2,9 +2,9 @@
{ {
public class ProxySettingLinux public class ProxySettingLinux
{ {
public static async Task SetProxy(string host, int port) public static async Task SetProxy(string host, int port, string exceptions)
{ {
var lstCmd = GetSetCmds(host, port); var lstCmd = GetSetCmds(host, port, exceptions);
await ExecCmd(lstCmd); await ExecCmd(lstCmd);
} }
@@ -29,25 +29,39 @@
} }
} }
private static List<CmdItem> GetSetCmds(string host, int port) private static List<CmdItem> GetSetCmds(string host, int port, string exceptions)
{ {
var isKde = IsKde(out var configDir); var isKde = IsKde(out var configDir);
List<string> lstType = ["", "http", "https", "socks", "ftp"]; List<string> lstType = ["", "http", "https", "socks", "ftp"];
List<CmdItem> lstCmd = []; List<CmdItem> lstCmd = [];
//GNOME
foreach (var type in lstType)
{
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
}
if (exceptions.IsNotEmpty())
{
lstCmd.AddRange(GetSetCmd4Gnome("exceptions", exceptions, 0));
}
if (isKde) if (isKde)
{ {
foreach (var type in lstType) foreach (var type in lstType)
{ {
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir)); lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
} }
} if (exceptions.IsNotEmpty())
else
{
foreach (var type in lstType)
{ {
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port)); lstCmd.AddRange(GetSetCmd4Kde("exceptions", exceptions, 0, configDir));
} }
// Notify system to reload
lstCmd.Add(new CmdItem()
{
Cmd = "dbus-send",
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
});
} }
return lstCmd; return lstCmd;
} }
@@ -57,44 +71,58 @@
var isKde = IsKde(out var configDir); var isKde = IsKde(out var configDir);
List<CmdItem> lstCmd = []; List<CmdItem> lstCmd = [];
//GNOME
lstCmd.Add(new CmdItem()
{
Cmd = "gsettings",
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
});
if (isKde) if (isKde)
{ {
lstCmd.Add(new CmdItem() lstCmd.Add(new CmdItem()
{ {
Cmd = "kwriteconfig5", Cmd = GetKdeVersion(),
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"] Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
}); });
}
else // Notify system to reload
{
lstCmd.Add(new CmdItem() lstCmd.Add(new CmdItem()
{ {
Cmd = "gsettings", Cmd = "dbus-send",
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"] Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
}); });
} }
return lstCmd; return lstCmd;
} }
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir) private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
{ {
List<CmdItem> lstCmd = []; List<CmdItem> lstCmd = [];
var cmd = GetKdeVersion();
if (type.IsNullOrEmpty()) if (type.IsNullOrEmpty())
{ {
lstCmd.Add(new() lstCmd.Add(new()
{ {
Cmd = "kwriteconfig5", Cmd = cmd,
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"] Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
}); });
} }
else if (type == "exceptions")
{
lstCmd.Add(new()
{
Cmd = cmd,
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "NoProxyFor", host]
});
}
else else
{ {
var type2 = type.Equals("https") ? "http" : type; var type2 = type.Equals("https") ? "http" : type;
lstCmd.Add(new CmdItem() lstCmd.Add(new CmdItem()
{ {
Cmd = "kwriteconfig5", Cmd = cmd,
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"] Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"]
}); });
} }
@@ -114,6 +142,14 @@
Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"] Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"]
}); });
} }
else if (type == "exceptions")
{
lstCmd.Add(new()
{
Cmd = "gsettings",
Arguments = ["set", $"org.gnome.system.proxy", "ignore-hosts", JsonUtils.Serialize(host.Split(','), false)]
});
}
else else
{ {
lstCmd.Add(new() lstCmd.Add(new()
@@ -136,7 +172,11 @@
{ {
configDir = "/home"; configDir = "/home";
var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP"); var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase); var desktop2 = Environment.GetEnvironmentVariable("XDG_SESSION_DESKTOP");
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase)
|| string.Equals(desktop, "plasma", StringComparison.OrdinalIgnoreCase)
|| string.Equals(desktop2, "KDE", StringComparison.OrdinalIgnoreCase)
|| string.Equals(desktop2, "plasma", StringComparison.OrdinalIgnoreCase);
if (isKde) if (isKde)
{ {
var homeDir = Environment.GetEnvironmentVariable("HOME"); var homeDir = Environment.GetEnvironmentVariable("HOME");
@@ -148,5 +188,15 @@
return isKde; return isKde;
} }
private static string GetKdeVersion()
{
var ver = Environment.GetEnvironmentVariable("KDE_SESSION_VERSION") ?? "0";
return ver switch
{
"6" => "kwriteconfig6",
_ => "kwriteconfig5"
};
}
} }
} }

View File

@@ -2,12 +2,99 @@
{ {
public class ProxySettingOSX public class ProxySettingOSX
{ {
public static async Task SetProxy(string host, int port) /// <summary>
/// 应用接口类型
/// </summary>
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge", "USB 10/100/1000 LAN"];
/// <summary>
/// 代理类型,对应 http,https,socks
/// </summary>
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
public static async Task SetProxy(string host, int port, string exceptions)
{ {
var lstInterface = await GetListNetworkServices();
var lstCmd = GetSetCmds(lstInterface, host, port, exceptions);
await ExecCmd(lstCmd);
} }
public static async Task UnsetProxy() public static async Task UnsetProxy()
{ {
var lstInterface = await GetListNetworkServices();
var lstCmd = GetUnsetCmds(lstInterface);
await ExecCmd(lstCmd);
}
private static async Task ExecCmd(List<CmdItem> lstCmd)
{
foreach (var cmd in lstCmd)
{
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
{
continue;
}
await Task.Delay(10);
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
}
}
private static List<CmdItem> GetSetCmds(List<string> lstInterface, string host, int port, string exceptions)
{
List<CmdItem> lstCmd = [];
foreach (var interf in lstInterface)
{
foreach (var type in LstTypes)
{
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = [$"-{type}", interf, host, port.ToString()]
});
}
if (exceptions.IsNotEmpty())
{
List<string> args = [$"-setproxybypassdomains", interf];
args.AddRange(exceptions.Split(','));
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = args
});
}
}
return lstCmd;
}
private static List<CmdItem> GetUnsetCmds(List<string> lstInterface)
{
List<CmdItem> lstCmd = [];
foreach (var interf in lstInterface)
{
foreach (var type in LstTypes)
{
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = [$"-{type}state", interf, "off"]
});
}
}
return lstCmd;
}
public static async Task<List<string>> GetListNetworkServices()
{
var services = await Utils.GetListNetworkServices();
if (services.IsNullOrEmpty())
{
return LstInterface;
}
var lst = services.Split(Environment.NewLine);
return lst.Length > 0 ? LstInterface.Intersect(lst).ToList() : LstInterface;
} }
} }
} }

View File

@@ -1,4 +1,4 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption; using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption;
namespace ServiceLib.Handler.SysProxy namespace ServiceLib.Handler.SysProxy
@@ -11,24 +11,24 @@ namespace ServiceLib.Handler.SysProxy
{ {
if (type == 1) if (type == 1)
{ {
RegWriteValue(_regPath, "ProxyEnable", 0); WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
RegWriteValue(_regPath, "ProxyServer", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
RegWriteValue(_regPath, "ProxyOverride", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
RegWriteValue(_regPath, "AutoConfigURL", string.Empty); WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
} }
if (type == 2) if (type == 2)
{ {
RegWriteValue(_regPath, "ProxyEnable", 1); WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 1);
RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
RegWriteValue(_regPath, "AutoConfigURL", string.Empty); WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
} }
else if (type == 4) else if (type == 4)
{ {
RegWriteValue(_regPath, "ProxyEnable", 0); WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
RegWriteValue(_regPath, "ProxyServer", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
RegWriteValue(_regPath, "ProxyOverride", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty); WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
} }
return true; return true;
} }
@@ -144,12 +144,12 @@ namespace ServiceLib.Handler.SysProxy
{ {
if (Environment.Is64BitOperatingSystem) if (Environment.Is64BitOperatingSystem)
{ {
nint opt = new(optionsPtr.ToInt64() + i * optSize); nint opt = new(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
else else
{ {
nint opt = new(optionsPtr.ToInt32() + i * optSize); nint opt = new(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false); Marshal.StructureToPtr(options[i], opt, false);
} }
} }
@@ -247,7 +247,7 @@ namespace ServiceLib.Handler.SysProxy
//[MarshalAs(UnmanagedType.)] //[MarshalAs(UnmanagedType.)]
public nint options; public nint options;
}; }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption public struct InternetConnectionOption
@@ -356,30 +356,5 @@ namespace ServiceLib.Handler.SysProxy
ref int lpcEntries // Number of entries written to the buffer ref int lpcEntries // Number of entries written to the buffer
); );
} }
private static void RegWriteValue(string path, string name, object value)
{
Microsoft.Win32.RegistryKey? regKey = null;
try
{
regKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(path);
if (string.IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
//Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
} }
} }

View File

@@ -1,6 +1,4 @@
using PacLib; namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy
{ {
public static class SysProxyHandler public static class SysProxyHandler
{ {
@@ -15,8 +13,8 @@ namespace ServiceLib.Handler.SysProxy
try try
{ {
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.http); var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
var portSocks = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks); var exceptions = config.SystemProxyItem.SystemProxyExceptions;
if (port <= 0) if (port <= 0)
{ {
return false; return false;
@@ -25,23 +23,18 @@ namespace ServiceLib.Handler.SysProxy
{ {
case ESysProxyType.ForcedChange when Utils.IsWindows(): case ESysProxyType.ForcedChange when Utils.IsWindows():
{ {
GetWindowsProxyString(config, port, portSocks, out var strProxy, out var strExceptions); GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2); ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
break; break;
} }
case ESysProxyType.ForcedChange when Utils.IsLinux(): case ESysProxyType.ForcedChange when Utils.IsLinux():
await ProxySettingLinux.SetProxy(Global.Loopback, port); await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
break; break;
case ESysProxyType.ForcedChange: case ESysProxyType.ForcedChange when Utils.IsOSX():
{ await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
if (Utils.IsOSX()) break;
{
await ProxySettingOSX.SetProxy(Global.Loopback, port);
}
break;
}
case ESysProxyType.ForcedClear when Utils.IsWindows(): case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy(); ProxySettingWindows.UnsetProxy();
break; break;
@@ -50,23 +43,13 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.UnsetProxy(); await ProxySettingLinux.UnsetProxy();
break; break;
case ESysProxyType.ForcedClear: case ESysProxyType.ForcedClear when Utils.IsOSX():
{ await ProxySettingOSX.UnsetProxy();
if (Utils.IsOSX()) break;
{
await ProxySettingOSX.UnsetProxy();
}
break;
}
case ESysProxyType.Pac when Utils.IsWindows(): case ESysProxyType.Pac when Utils.IsWindows():
{ await SetWindowsProxyPac(port);
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac); break;
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
break;
}
} }
if (type != ESysProxyType.Pac && Utils.IsWindows()) if (type != ESysProxyType.Pac && Utils.IsWindows())
@@ -81,12 +64,12 @@ namespace ServiceLib.Handler.SysProxy
return true; return true;
} }
private static void GetWindowsProxyString(Config config, int port, int portSocks, out string strProxy, out string strExceptions) private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
{ {
strExceptions = ""; strExceptions = config.SystemProxyItem.SystemProxyExceptions;
if (config.SystemProxyItem.NotProxyLocalAddress) if (config.SystemProxyItem.NotProxyLocalAddress)
{ {
strExceptions = $"<local>;{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}"; strExceptions = $"<local>;{strExceptions}";
} }
strProxy = string.Empty; strProxy = string.Empty;
@@ -99,8 +82,16 @@ namespace ServiceLib.Handler.SysProxy
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
.Replace("{ip}", Global.Loopback) .Replace("{ip}", Global.Loopback)
.Replace("{http_port}", port.ToString()) .Replace("{http_port}", port.ToString())
.Replace("{socks_port}", portSocks.ToString()); .Replace("{socks_port}", port.ToString());
} }
} }
private static async Task SetWindowsProxyPac(int port)
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
}
} }
} }

View File

@@ -1,6 +1,6 @@
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
public class CheckUpdateItem public class CheckUpdateModel
{ {
public bool? IsSelected { get; set; } public bool? IsSelected { get; set; }
public string? CoreType { get; set; } public string? CoreType { get; set; }

View File

@@ -15,15 +15,15 @@
public bool IsRunningCore(ECoreType type) public bool IsRunningCore(ECoreType type)
{ {
if (type == ECoreType.Xray && RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5) switch (type)
{ {
return true; case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
return true;
default:
return false;
} }
if (type == ECoreType.sing_box && RunningCoreType is ECoreType.sing_box or ECoreType.mihomo)
{
return true;
}
return false;
} }
#endregion property #endregion property
@@ -46,6 +46,7 @@
public ClashUIItem ClashUIItem { get; set; } public ClashUIItem ClashUIItem { get; set; }
public SystemProxyItem SystemProxyItem { get; set; } public SystemProxyItem SystemProxyItem { get; set; }
public WebDavItem WebDavItem { get; set; } public WebDavItem WebDavItem { get; set; }
public CheckUpdateItem CheckUpdateItem { 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

@@ -24,21 +24,16 @@
public class InItem public class InItem
{ {
public int LocalPort { get; set; } public int LocalPort { get; set; }
public string Protocol { get; set; } public string Protocol { get; set; }
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 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; }
public string User { get; set; } public string User { get; set; }
public string Pass { get; set; } public string Pass { get; set; }
public bool SecondLocalPortEnabled { get; set; }
} }
[Serializable] [Serializable]
@@ -81,13 +76,13 @@
public int AutoUpdateInterval { get; set; } public int AutoUpdateInterval { get; set; }
public bool CheckPreReleaseUpdate { get; set; } = false;
public bool EnableSecurityProtocolTls13 { get; set; } public bool EnableSecurityProtocolTls13 { get; set; }
public int TrayMenuServersLimit { get; set; } = 20; public int TrayMenuServersLimit { get; set; } = 20;
public bool EnableHWA { get; set; } = false; public bool EnableHWA { get; set; } = false;
public bool EnableLog { get; set; } = true;
} }
[Serializable] [Serializable]
@@ -116,6 +111,7 @@
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; } public bool AutoHideStartup { get; set; }
public bool Hide2TrayWhenClose { get; set; }
public List<ColumnItem> MainColumnItem { get; set; } public List<ColumnItem> MainColumnItem { get; set; }
public bool ShowInTaskbar { get; set; } public bool ShowInTaskbar { get; set; }
} }
@@ -161,6 +157,7 @@
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; } public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPwd { get; set; }
} }
[Serializable] [Serializable]
@@ -169,6 +166,7 @@
public int SpeedTestTimeout { get; set; } public int SpeedTestTimeout { get; set; }
public string SpeedTestUrl { get; set; } public string SpeedTestUrl { get; set; }
public string SpeedPingTestUrl { get; set; } public string SpeedPingTestUrl { get; set; }
public int SpeedTestPageSize { get; set; }
} }
[Serializable] [Serializable]
@@ -178,7 +176,6 @@
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; }
} }
[Serializable] [Serializable]
@@ -221,7 +218,6 @@
public int ProxiesSorting { get; set; } public int ProxiesSorting { get; set; }
public bool ProxiesAutoRefresh { get; set; } public bool ProxiesAutoRefresh { get; set; }
public int ProxiesAutoDelayTestInterval { get; set; } = 10; public int ProxiesAutoDelayTestInterval { get; set; } = 10;
public int ConnectionsSorting { get; set; }
public bool ConnectionsAutoRefresh { get; set; } public bool ConnectionsAutoRefresh { get; set; }
public int ConnectionsRefreshInterval { get; set; } = 2; public int ConnectionsRefreshInterval { get; set; } = 2;
} }
@@ -243,4 +239,11 @@
public string? Password { get; set; } public string? Password { get; set; }
public string? DirName { get; set; } public string? DirName { get; set; }
} }
[Serializable]
public class CheckUpdateItem
{
public bool CheckPreReleaseUpdate { get; set; }
public List<string>? SelectedCoreTypes { get; set; }
}
} }

View File

@@ -12,6 +12,8 @@
public string? DownloadUrlWinArm64 { get; set; } public string? DownloadUrlWinArm64 { get; set; }
public string? DownloadUrlLinux64 { get; set; } public string? DownloadUrlLinux64 { get; set; }
public string? DownloadUrlLinuxArm64 { get; set; } public string? DownloadUrlLinuxArm64 { get; set; }
public string? DownloadUrlOSX64 { get; set; }
public string? DownloadUrlOSXArm64 { get; set; }
public string? Match { get; set; } public string? Match { get; set; }
public string? VersionArg { get; set; } public string? VersionArg { get; set; }
public bool RedirectInfo { get; set; } public bool RedirectInfo { get; set; }

View File

@@ -0,0 +1,13 @@
namespace ServiceLib.Models
{
internal class IPAPIInfo
{
public string? ip { get; set; }
public string? city { get; set; }
public string? region { get; set; }
public string? region_code { get; set; }
public string? country { get; set; }
public string? country_name { get; set; }
public string? country_code { get; set; }
}
}

View File

@@ -30,44 +30,25 @@ namespace ServiceLib.Models
public string GetSummary() public string GetSummary()
{ {
string summary = string.Format("[{0}] ", (ConfigType).ToString()); var summary = $"[{(ConfigType).ToString()}] ";
string[] arrAddr = Address.Split('.'); var arrAddr = Address.Split('.');
string addr; var addr = arrAddr.Length switch
if (arrAddr.Length > 2)
{ {
addr = $"{arrAddr.First()}***{arrAddr.Last()}"; > 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
} > 1 => $"***{arrAddr.Last()}",
else if (arrAddr.Length > 1) _ => Address
};
summary += ConfigType switch
{ {
addr = $"***{arrAddr.Last()}"; EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}",
} _ => $"{Remarks}({addr}:{Port})"
else };
{
addr = Address;
}
switch (ConfigType)
{
case EConfigType.Custom:
summary += string.Format("[{1}]{0}", Remarks, CoreType.ToString());
break;
default:
summary += string.Format("{0}({1}:{2})", Remarks, addr, Port);
break;
}
return summary; return summary;
} }
public List<string>? GetAlpn() public List<string>? GetAlpn()
{ {
if (Utils.IsNullOrEmpty(Alpn)) return Utils.IsNullOrEmpty(Alpn) ? null : Utils.String2List(Alpn);
{
return null;
}
else
{
return Utils.String2List(Alpn);
}
} }
public string GetNetwork() public string GetNetwork()
@@ -110,5 +91,6 @@ namespace ServiceLib.Models
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; }
public string Extra { get; set; }
} }
} }

View File

@@ -78,8 +78,7 @@
public int? listen_port { get; set; } public int? listen_port { get; set; }
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 List<string>? 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; }

View File

@@ -33,5 +33,7 @@ namespace ServiceLib.Models
public string? NextProfile { get; set; } public string? NextProfile { get; set; }
public int? PreSocksPort { get; set; } public int? PreSocksPort { get; set; }
public string? Memo { get; set; }
} }
} }

View File

@@ -1,61 +1,34 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
/// <summary>
/// v2ray配置文件实体类 例子SampleConfig.txt
/// </summary>
public class V2rayConfig public class V2rayConfig
{ {
/// <summary>
/// Properties that do not belong to Ray
/// </summary>
public string? remarks { get; set; } public string? remarks { get; set; }
/// <summary>
/// 日志配置
/// </summary>
public Log4Ray log { get; set; } public Log4Ray log { get; set; }
/// <summary>
/// 传入连接配置
/// </summary>
public List<Inbounds4Ray> inbounds { get; set; } public List<Inbounds4Ray> inbounds { get; set; }
/// <summary>
/// 传出连接配置
/// </summary>
public List<Outbounds4Ray> outbounds { get; set; } public List<Outbounds4Ray> outbounds { get; set; }
/// <summary> public Stats4Ray? stats { get; set; }
/// 统计需要, 空对象
/// </summary>
public Stats4Ray stats { get; set; }
/// </summary> public Metrics4Ray? metrics { get; set; }
public API4Ray api { get; set; }
/// </summary> public Policy4Ray? policy { get; set; }
public Policy4Ray policy { get; set; }
/// <summary>
/// DNS 配置
/// </summary>
public object dns { get; set; } public object dns { get; set; }
/// <summary>
/// 路由配置
/// </summary>
public Routing4Ray routing { get; set; } public Routing4Ray routing { get; set; }
} }
public class Stats4Ray public class Stats4Ray
{ }; { }
public class API4Ray public class Metrics4Ray
{ {
public string tag { get; set; } public string tag { get; set; }
public List<string> services { get; set; }
} }
public class Policy4Ray public class Policy4Ray
@@ -71,124 +44,59 @@ namespace ServiceLib.Models
public class Log4Ray public class Log4Ray
{ {
/// <summary> public string? access { get; set; }
///
/// </summary>
public string access { get; set; }
/// <summary> public string? error { get; set; }
///
/// </summary>
public string error { get; set; }
/// <summary> public string? loglevel { get; set; }
///
/// </summary>
public string loglevel { get; set; }
} }
public class Inbounds4Ray public class Inbounds4Ray
{ {
public string tag { get; set; } public string tag { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary>
///
/// </summary>
public string listen { get; set; } public string listen { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; } public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Sniffing4Ray sniffing { get; set; } public Sniffing4Ray sniffing { get; set; }
/// <summary>
///
/// </summary>
public Inboundsettings4Ray settings { get; set; } public Inboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; }
} }
public class Inboundsettings4Ray public class Inboundsettings4Ray
{ {
/// <summary> public string? auth { get; set; }
///
/// </summary>
public string auth { get; set; }
/// <summary> public bool? udp { get; set; }
///
/// </summary>
public bool udp { get; set; }
/// <summary> public string? ip { get; set; }
///
/// </summary>
public string ip { get; set; }
/// <summary> public string? address { get; set; }
/// api 使用
/// </summary>
public string address { get; set; }
/// <summary> public List<UsersItem4Ray>? clients { get; set; }
///
/// </summary>
public List<UsersItem4Ray> clients { get; set; }
/// <summary> public string? decryption { get; set; }
/// VLESS
/// </summary>
public string decryption { get; set; }
public bool allowTransparent { get; set; } public bool? allowTransparent { get; set; }
public List<AccountsItem4Ray> accounts { get; set; } public List<AccountsItem4Ray>? accounts { get; set; }
} }
public class UsersItem4Ray public class UsersItem4Ray
{ {
/// <summary> public string? id { get; set; }
///
/// </summary>
public string id { get; set; }
/// <summary> public int? alterId { get; set; }
///
/// </summary>
public int alterId { get; set; }
/// <summary> public string? email { get; set; }
///
/// </summary>
public string email { get; set; }
/// <summary> public string? security { get; set; }
///
/// </summary>
public string security { get; set; }
/// <summary> public string? encryption { get; set; }
/// VLESS
/// </summary>
public string encryption { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string? flow { get; set; } public string? flow { get; set; }
} }
@@ -201,57 +109,27 @@ namespace ServiceLib.Models
public class Outbounds4Ray public class Outbounds4Ray
{ {
/// <summary>
/// 默认值agentout
/// </summary>
public string tag { get; set; } public string tag { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; } public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Outboundsettings4Ray settings { get; set; } public Outboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; } public StreamSettings4Ray streamSettings { get; set; }
/// <summary>
///
/// </summary>
public Mux4Ray mux { get; set; } public Mux4Ray mux { get; set; }
} }
public class Outboundsettings4Ray public class Outboundsettings4Ray
{ {
/// <summary>
///
/// </summary>
public List<VnextItem4Ray>? vnext { get; set; } public List<VnextItem4Ray>? vnext { get; set; }
/// <summary> public List<ServersItem4Ray>? servers { get; set; }
///
/// </summary>
public List<ServersItem4Ray> servers { get; set; }
/// <summary> public Response4Ray? response { get; set; }
///
/// </summary>
public Response4Ray response { get; set; }
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public int? userLevel { get; set; } public int? userLevel { get; set; }
public FragmentItem4Ray? fragment { get; set; } public FragmentItem4Ray? fragment { get; set; }
@@ -259,85 +137,40 @@ namespace ServiceLib.Models
public class VnextItem4Ray public class VnextItem4Ray
{ {
/// <summary>
///
/// </summary>
public string address { get; set; } public string address { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary>
///
/// </summary>
public List<UsersItem4Ray> users { get; set; } public List<UsersItem4Ray> users { get; set; }
} }
public class ServersItem4Ray public class ServersItem4Ray
{ {
/// <summary>
///
/// </summary>
public string email { get; set; } public string email { get; set; }
/// <summary>
///
/// </summary>
public string address { get; set; } public string address { get; set; }
/// <summary>
///
/// </summary>
public string? method { get; set; } public string? method { get; set; }
/// <summary>
///
/// </summary>
public bool? ota { get; set; } public bool? ota { get; set; }
/// <summary>
///
/// </summary>
public string? password { get; set; } public string? password { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; } public int? level { get; set; }
/// <summary>
/// trojan
/// </summary>
public string flow { get; set; } public string flow { get; set; }
/// <summary>
///
/// </summary>
public List<SocksUsersItem4Ray> users { get; set; } public List<SocksUsersItem4Ray> users { get; set; }
} }
public class SocksUsersItem4Ray public class SocksUsersItem4Ray
{ {
/// <summary>
///
/// </summary>
public string user { get; set; } public string user { get; set; }
/// <summary>
///
/// </summary>
public string pass { get; set; } public string pass { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; } public int? level { get; set; }
} }
@@ -351,17 +184,11 @@ namespace ServiceLib.Models
public class Response4Ray public class Response4Ray
{ {
/// <summary>
///
/// </summary>
public string type { get; set; } public string type { get; set; }
} }
public class Dns4Ray public class Dns4Ray
{ {
/// <summary>
///
/// </summary>
public List<string> servers { get; set; } public List<string> servers { get; set; }
} }
@@ -373,19 +200,10 @@ namespace ServiceLib.Models
public class Routing4Ray public class Routing4Ray
{ {
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public string? domainMatcher { get; set; } public string? domainMatcher { get; set; }
/// <summary>
///
/// </summary>
public List<RulesItem4Ray> rules { get; set; } public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; } public List<BalancersItem4Ray>? balancers { get; set; }
@@ -426,87 +244,39 @@ namespace ServiceLib.Models
public class StreamSettings4Ray public class StreamSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string network { get; set; } public string network { get; set; }
/// <summary>
///
/// </summary>
public string security { get; set; } public string security { get; set; }
/// <summary>
///
/// </summary>
public TlsSettings4Ray? tlsSettings { get; set; } public TlsSettings4Ray? tlsSettings { get; set; }
/// <summary>
/// Tcp传输额外设置
/// </summary>
public TcpSettings4Ray? tcpSettings { get; set; } public TcpSettings4Ray? tcpSettings { get; set; }
/// <summary>
/// Kcp传输额外设置
/// </summary>
public KcpSettings4Ray? kcpSettings { get; set; } public KcpSettings4Ray? kcpSettings { get; set; }
/// <summary>
/// ws传输额外设置
/// </summary>
public WsSettings4Ray? wsSettings { get; set; } public WsSettings4Ray? wsSettings { get; set; }
/// <summary>
///
/// </summary>
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; } public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
/// <summary> public XhttpSettings4Ray? xhttpSettings { get; set; }
///
/// </summary>
public SplithttpSettings4Ray? splithttpSettings { get; set; }
/// <summary>
/// h2传输额外设置
/// </summary>
public HttpSettings4Ray? httpSettings { get; set; } public HttpSettings4Ray? httpSettings { get; set; }
/// <summary>
/// QUIC
/// </summary>
public QuicSettings4Ray? quicSettings { get; set; } public QuicSettings4Ray? quicSettings { get; set; }
/// <summary>
/// VLESS only
/// </summary>
public TlsSettings4Ray? realitySettings { get; set; } public TlsSettings4Ray? realitySettings { get; set; }
/// <summary>
/// grpc
/// </summary>
public GrpcSettings4Ray? grpcSettings { get; set; } public GrpcSettings4Ray? grpcSettings { get; set; }
/// <summary>
/// sockopt
/// </summary>
public Sockopt4Ray? sockopt { get; set; } public Sockopt4Ray? sockopt { get; set; }
} }
public class TlsSettings4Ray public class TlsSettings4Ray
{ {
/// <summary>
/// 是否允许不安全连接(用于客户端)
/// </summary>
public bool? allowInsecure { get; set; } public bool? allowInsecure { get; set; }
/// <summary>
///
/// </summary>
public string? serverName { get; set; } public string? serverName { get; set; }
/// <summary>
///
/// </summary>
public List<string>? alpn { get; set; } public List<string>? alpn { get; set; }
public string? fingerprint { get; set; } public string? fingerprint { get; set; }
@@ -519,157 +289,83 @@ namespace ServiceLib.Models
public class TcpSettings4Ray public class TcpSettings4Ray
{ {
/// <summary>
/// 数据包头部伪装设置
/// </summary>
public Header4Ray header { get; set; } public Header4Ray header { get; set; }
} }
public class Header4Ray public class Header4Ray
{ {
/// <summary>
/// 伪装
/// </summary>
public string type { get; set; } public string type { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object request { get; set; } public object request { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object response { get; set; } public object response { get; set; }
} }
public class KcpSettings4Ray public class KcpSettings4Ray
{ {
/// <summary>
///
/// </summary>
public int mtu { get; set; } public int mtu { get; set; }
/// <summary>
///
/// </summary>
public int tti { get; set; } public int tti { get; set; }
/// <summary>
///
/// </summary>
public int uplinkCapacity { get; set; } public int uplinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public int downlinkCapacity { get; set; } public int downlinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public bool congestion { get; set; } public bool congestion { get; set; }
/// <summary>
///
/// </summary>
public int readBufferSize { get; set; } public int readBufferSize { get; set; }
/// <summary>
///
/// </summary>
public int writeBufferSize { get; set; } public int writeBufferSize { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; } public Header4Ray header { get; set; }
/// <summary>
///
/// </summary>
public string seed { get; set; } public string seed { get; set; }
} }
public class WsSettings4Ray public class WsSettings4Ray
{ {
/// <summary> public string? path { get; set; }
/// public string? host { get; set; }
/// </summary>
public string path { get; set; }
/// <summary>
///
/// </summary>
public Headers4Ray headers { get; set; } public Headers4Ray headers { get; set; }
} }
public class Headers4Ray public class Headers4Ray
{ {
/// <summary>
///
/// </summary>
public string Host { get; set; } public string Host { get; set; }
/// <summary>
/// 用户代理
/// </summary>
[JsonPropertyName("User-Agent")] [JsonPropertyName("User-Agent")]
public string UserAgent { get; set; } public string UserAgent { get; set; }
} }
public class HttpupgradeSettings4Ray public class HttpupgradeSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string? path { get; set; } public string? path { get; set; }
/// <summary>
///
/// </summary>
public string? host { get; set; } public string? host { get; set; }
} }
public class SplithttpSettings4Ray public class XhttpSettings4Ray
{ {
public string? path { get; set; } public string? path { get; set; }
public string? host { get; set; } public string? host { get; set; }
public string? mode { get; set; }
public int? maxUploadSize { get; set; } public object? extra { get; set; }
public int? maxConcurrentUploads { get; set; }
} }
public class HttpSettings4Ray public class HttpSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string? path { get; set; } public string? path { get; set; }
/// <summary>
///
/// </summary>
public List<string>? host { get; set; } public List<string>? host { get; set; }
} }
public class QuicSettings4Ray public class QuicSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string security { get; set; } public string security { get; set; }
/// <summary>
///
/// </summary>
public string key { get; set; } public string key { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; } public Header4Ray header { get; set; }
} }
@@ -686,14 +382,8 @@ namespace ServiceLib.Models
public class AccountsItem4Ray public class AccountsItem4Ray
{ {
/// <summary>
///
/// </summary>
public string user { get; set; } public string user { get; set; }
/// <summary>
///
/// </summary>
public string pass { get; set; } public string pass { get; set; }
} }

View File

@@ -0,0 +1,20 @@
using System.Collections;
namespace ServiceLib.Models
{
internal class V2rayMetricsVars
{
public V2rayMetricsVarsStats? stats { get; set; }
}
}
public class V2rayMetricsVarsStats
{
public Hashtable? outbound { get; set; }
}
public class V2rayMetricsVarsLink
{
public long downlink { get; set; }
public long uplink { get; set; }
}

View File

@@ -447,6 +447,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Remarks Memo 的本地化字符串。
/// </summary>
public static string LvMemo {
get {
return ResourceManager.GetString("LvMemo", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。 /// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。
/// </summary> /// </summary>
@@ -870,6 +879,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Are you sure to exit? 的本地化字符串。
/// </summary>
public static string menuExitTips {
get {
return ResourceManager.GetString("menuExitTips", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Export selected server for complete configuration 的本地化字符串。 /// 查找类似 Export selected server for complete configuration 的本地化字符串。
/// </summary> /// </summary>
@@ -1230,6 +1248,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Iran 的本地化字符串。
/// </summary>
public static string menuRegionalPresetsIran {
get {
return ResourceManager.GetString("menuRegionalPresetsIran", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Russia 的本地化字符串。 /// 查找类似 Russia 的本地化字符串。
/// </summary> /// </summary>
@@ -1347,24 +1374,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Basic Function 的本地化字符串。
/// </summary>
public static string menuRoutingBasic {
get {
return ResourceManager.GetString("menuRoutingBasic", resourceCulture);
}
}
/// <summary>
/// 查找类似 Import Basic Rules 的本地化字符串。
/// </summary>
public static string menuRoutingBasicImportRules {
get {
return ResourceManager.GetString("menuRoutingBasicImportRules", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 RoutingRuleDetailsSetting 的本地化字符串。 /// 查找类似 RoutingRuleDetailsSetting 的本地化字符串。
/// </summary> /// </summary>
@@ -2599,6 +2608,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 socks: local port, socks2: second local port, socks3: LAN port 的本地化字符串。
/// </summary>
public static string TbRoutingInboundTagTips {
get {
return ResourceManager.GetString("TbRoutingInboundTagTips", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Domain 的本地化字符串。 /// 查找类似 Domain 的本地化字符串。
/// </summary> /// </summary>
@@ -2914,6 +2932,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Sniffing type 的本地化字符串。
/// </summary>
public static string TbSettingsDestOverride {
get {
return ResourceManager.GetString("TbSettingsDestOverride", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Outbound DNS address 的本地化字符串。 /// 查找类似 Outbound DNS address 的本地化字符串。
/// </summary> /// </summary>
@@ -3058,6 +3085,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Exception. Do not use proxy server for addresses,with a comma (,) 的本地化字符串。
/// </summary>
public static string TbSettingsExceptionTip2 {
get {
return ResourceManager.GetString("TbSettingsExceptionTip2", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Follow System Theme 的本地化字符串。 /// 查找类似 Follow System Theme 的本地化字符串。
/// </summary> /// </summary>
@@ -3085,6 +3121,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Hide to tray when closing the window 的本地化字符串。
/// </summary>
public static string TbSettingsHide2TrayWhenClose {
get {
return ResourceManager.GetString("TbSettingsHide2TrayWhenClose", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 HTTP Port 的本地化字符串。 /// 查找类似 HTTP Port 的本地化字符串。
/// </summary> /// </summary>
@@ -3130,6 +3175,42 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 System sudo password 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPassword {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPassword", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please set the sudo password in Tun mode settings first 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordIsEmpty {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordIsEmpty", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please do not run this app with sudo 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordNotSudoRunApp {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordNotSudoRunApp", resourceCulture);
}
}
/// <summary>
/// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordTip {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Enable Log 的本地化字符串。 /// 查找类似 Enable Log 的本地化字符串。
/// </summary> /// </summary>
@@ -3247,6 +3328,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Enable second mixed port 的本地化字符串。
/// </summary>
public static string TbSettingsSecondLocalPortEnabled {
get {
return ResourceManager.GetString("TbSettingsSecondLocalPortEnabled", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。 /// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
/// </summary> /// </summary>
@@ -3266,7 +3356,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 SOCKS Port 的本地化字符串。 /// 查找类似 Mixed Port 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsSocksPort { public static string TbSettingsSocksPort {
get { get {
@@ -3275,7 +3365,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6; 的本地化字符串。 /// 查找类似 Pac port = +3; Xray API port = +4; mihomo API port = +5; 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsSocksPortTip { public static string TbSettingsSocksPortTip {
get { get {
@@ -3292,6 +3382,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Number per time for auto batch during speedtest(max 1000) 的本地化字符串。
/// </summary>
public static string TbSettingsSpeedTestPageSize {
get {
return ResourceManager.GetString("TbSettingsSpeedTestPageSize", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。 /// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
/// </summary> /// </summary>
@@ -3581,7 +3680,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 The ping of current service: {0} ms 的本地化字符串。 /// 查找类似 The delay : {0} ms, {1} 的本地化字符串。
/// </summary> /// </summary>
public static string TestMeOutput { public static string TestMeOutput {
get { get {
@@ -3643,6 +3742,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 XHTTP Extra raw JSON, format: { XHTTPObject } 的本地化字符串。
/// </summary>
public static string TransportExtraTip {
get {
return ResourceManager.GetString("TransportExtraTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 *tcp camouflage type 的本地化字符串。 /// 查找类似 *tcp camouflage type 的本地化字符串。
/// </summary> /// </summary>
@@ -3680,7 +3788,16 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *ws/httpupgrade/splithttp path 的本地化字符串。 /// 查找类似 *xhttp mode 的本地化字符串。
/// </summary>
public static string TransportHeaderTypeTip5 {
get {
return ResourceManager.GetString("TransportHeaderTypeTip5", resourceCulture);
}
}
/// <summary>
/// 查找类似 *ws/httpupgrade/xhttp path 的本地化字符串。
/// </summary> /// </summary>
public static string TransportPathTip1 { public static string TransportPathTip1 {
get { get {
@@ -3734,7 +3851,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *ws/httpupgrade/splithttp host 的本地化字符串。 /// 查找类似 *ws/httpupgrade/xhttp host 的本地化字符串。
/// </summary> /// </summary>
public static string TransportRequestHostTip2 { public static string TransportRequestHostTip2 {
get { get {

View File

@@ -118,7 +118,7 @@
<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="BatchExportURLSuccessfully" xml:space="preserve"> <data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>Batch export share URL to clipboard successfully</value> <value>ارسال دسته ای آدرس اینترنتی اشتراک گذاری به کلیپ بورد با موفقیت.</value>
</data> </data>
<data name="CheckServerSettings" xml:space="preserve"> <data name="CheckServerSettings" xml:space="preserve">
<value>لطفا ابتدا تنظیمات سرور را بررسی کنید</value> <value>لطفا ابتدا تنظیمات سرور را بررسی کنید</value>
@@ -136,7 +136,7 @@
<value>دانلود</value> <value>دانلود</value>
</data> </data>
<data name="DownloadYesNo" xml:space="preserve"> <data name="DownloadYesNo" xml:space="preserve">
<value>Whether to download? {0}</value> <value>آیا برای دانلود؟ {0}</value>
</data> </data>
<data name="FailedConversionConfiguration" xml:space="preserve"> <data name="FailedConversionConfiguration" xml:space="preserve">
<value>تبدیل فایل پیکربندی انجام نشد</value> <value>تبدیل فایل پیکربندی انجام نشد</value>
@@ -226,7 +226,7 @@
<value>هیچ اشتراک معتبری تنظیم نشده است</value> <value>هیچ اشتراک معتبری تنظیم نشده است</value>
</data> </data>
<data name="MsgParsingSuccessfully" xml:space="preserve"> <data name="MsgParsingSuccessfully" xml:space="preserve">
<value>Resolve {0} successfully</value> <value>حل {0} با موفقیت</value>
</data> </data>
<data name="MsgStartGettingSubscriptions" xml:space="preserve"> <data name="MsgStartGettingSubscriptions" xml:space="preserve">
<value>شروع به دریافت اشتراک شد</value> <value>شروع به دریافت اشتراک شد</value>
@@ -253,19 +253,19 @@
<value>هسته با موفقیت بروزرسانی شد! راه اندازی مجدد سرویس...</value> <value>هسته با موفقیت بروزرسانی شد! راه اندازی مجدد سرویس...</value>
</data> </data>
<data name="NonvmessOrssProtocol" xml:space="preserve"> <data name="NonvmessOrssProtocol" xml:space="preserve">
<value>Non-VMess or ss protocol</value> <value>پروتکل غیر VMess یا ss</value>
</data> </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>فایل Core (نام فایل: {1}) در زیر پوشه ({0}) یافت نشد، لطفاً آن را دانلود کرده و در پوشه قرار دهید، آدرس دانلود: {2}</value>
</data> </data>
<data name="NoValidQRcodeFound" xml:space="preserve"> <data name="NoValidQRcodeFound" xml:space="preserve">
<value>Scan completed, no valid QR code found</value> <value>اسکن کامل شد، QRcode معتبری یافت نشد</value>
</data> </data>
<data name="OperationFailed" xml:space="preserve"> <data name="OperationFailed" xml:space="preserve">
<value> عملیات انجام نشد، لطفا بررسی کنید و دوباره امتحان کنید</value> <value> عملیات انجام نشد، لطفا بررسی کنید و دوباره امتحان کنید</value>
</data> </data>
<data name="PleaseFillRemarks" xml:space="preserve"> <data name="PleaseFillRemarks" xml:space="preserve">
<value>Please Fill Remarks</value> <value>لطفا ملاحظات را پر کنید</value>
</data> </data>
<data name="PleaseSelectEncryption" xml:space="preserve"> <data name="PleaseSelectEncryption" xml:space="preserve">
<value>لطفاً روش رمزگذاری را انتخاب کنید</value> <value>لطفاً روش رمزگذاری را انتخاب کنید</value>
@@ -277,16 +277,16 @@
<value>لطفا ابتدا سرور را انتخاب کنید</value> <value>لطفا ابتدا سرور را انتخاب کنید</value>
</data> </data>
<data name="RemoveDuplicateServerResult" xml:space="preserve"> <data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>Servers deduplication completed. Old: {0}, New: {1}.</value> <value>حذف مجدد سرورها تکمیل شد. قدیمی: {0}، جدید: {1}.</value>
</data> </data>
<data name="RemoveServer" xml:space="preserve"> <data name="RemoveServer" xml:space="preserve">
<value>آیا مطمئن هستید که سرور را حذف می کنید؟</value> <value>آیا مطمئن هستید که سرور را حذف می کنید؟</value>
</data> </data>
<data name="SaveClientConfigurationIn" xml:space="preserve"> <data name="SaveClientConfigurationIn" xml:space="preserve">
<value>The client configuration file is saved at: {0}</value> <value>فایل پیکربندی کلاینت در این آدرس ذخیره می شود: {0}</value>
</data> </data>
<data name="StartService" xml:space="preserve"> <data name="StartService" xml:space="preserve">
<value>Start service ({0})...</value> <value>شروع سرویس ({0})...</value>
</data> </data>
<data name="SuccessfulConfiguration" xml:space="preserve"> <data name="SuccessfulConfiguration" xml:space="preserve">
<value>پیکربندی با موفقیت انجام شد <value>پیکربندی با موفقیت انجام شد
@@ -302,7 +302,7 @@
<value>اسکن URL وارد کردن با موفقیت</value> <value>اسکن URL وارد کردن با موفقیت</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>پینگ سرویس فعلی: {0} ms</value> <value>پینگ سرویس فعلی: {0} ms, {1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>موفقیت عملیات</value> <value>موفقیت عملیات</value>
@@ -317,19 +317,19 @@
<value>{0},یکی از مورد نیاز.</value> <value>{0},یکی از مورد نیاز.</value>
</data> </data>
<data name="LvRemarks" xml:space="preserve"> <data name="LvRemarks" xml:space="preserve">
<value>Remarks</value> <value>ملاحظات</value>
</data> </data>
<data name="LvUrl" xml:space="preserve"> <data name="LvUrl" xml:space="preserve">
<value>Url(Optional)</value> <value>آدرس اینترنتی (اختیاری)</value>
</data> </data>
<data name="LvCount" xml:space="preserve"> <data name="LvCount" xml:space="preserve">
<value>Count</value> <value>شمارش</value>
</data> </data>
<data name="MsgNeedUrl" xml:space="preserve"> <data name="MsgNeedUrl" xml:space="preserve">
<value>Please fill in the address (Url)</value> <value>لطفا آدرس (آدرس اینترنتی) را وارد کنید</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>آیا می خواهید قوانین را اضافه کنید؟ برای ضمیمه بله را انتخاب کنید، در غیر این صورت جایگزین کنید</value>
</data> </data>
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve"> <data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
<value>دانلود GeoFile: {0} با موفقیت</value> <value>دانلود GeoFile: {0} با موفقیت</value>
@@ -386,10 +386,10 @@
<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>کلید میانبر جهانی {0} ثبت نشد، دلیل کلید میانبر جهانی {0} ثبت ناموفق بود، دلیل {1}{1}</value>
</data> </data>
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve"> <data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
<value>Global hotkey {0} registered successfully</value> <value>کلید میانبر جهانی {0} با موفقیت ثبت شد</value>
</data> </data>
<data name="UngroupedServers" xml:space="preserve"> <data name="UngroupedServers" xml:space="preserve">
<value>گروه بندی نشده</value> <value>گروه بندی نشده</value>
@@ -398,7 +398,7 @@
<value>همه سرورها</value> <value>همه سرورها</value>
</data> </data>
<data name="FillServerAddressCustom" xml:space="preserve"> <data name="FillServerAddressCustom" xml:space="preserve">
<value>Please browse to import server configuration</value> <value>لطفاً برای وارد کردن پیکربندی سرور مرور کنید</value>
</data> </data>
<data name="Speedtesting" xml:space="preserve"> <data name="Speedtesting" xml:space="preserve">
<value>درحال تست کردن...</value> <value>درحال تست کردن...</value>
@@ -593,7 +593,7 @@
<value>آدرس</value> <value>آدرس</value>
</data> </data>
<data name="TbAllowInsecure" xml:space="preserve"> <data name="TbAllowInsecure" xml:space="preserve">
<value>اجازه ناامن</value> <value>اعطای مجوز ناامن</value>
</data> </data>
<data name="TbAlpn" xml:space="preserve"> <data name="TbAlpn" xml:space="preserve">
<value>Alpn</value> <value>Alpn</value>
@@ -602,10 +602,10 @@
<value>AlterId</value> <value>AlterId</value>
</data> </data>
<data name="TbFingerprint" xml:space="preserve"> <data name="TbFingerprint" xml:space="preserve">
<value>Fingerprint</value> <value>اثرانگشت</value>
</data> </data>
<data name="TbHeaderType" xml:space="preserve"> <data name="TbHeaderType" xml:space="preserve">
<value>Camouflage type</value> <value>نوع Camouflage</value>
</data> </data>
<data name="TbId" xml:space="preserve"> <data name="TbId" xml:space="preserve">
<value>UUID(id)</value> <value>UUID(id)</value>
@@ -620,13 +620,13 @@
<value>پورت</value> <value>پورت</value>
</data> </data>
<data name="TbRemarks" xml:space="preserve"> <data name="TbRemarks" xml:space="preserve">
<value>Alias (remarks)</value> <value>نام مستعار (ملاحظات)</value>
</data> </data>
<data name="TbRequestHost" xml:space="preserve"> <data name="TbRequestHost" xml:space="preserve">
<value>Camouflage domain(host)</value> <value>Camouflage domain(host)</value>
</data> </data>
<data name="TbSecurity" xml:space="preserve"> <data name="TbSecurity" xml:space="preserve">
<value>Encryption method (security)</value> <value>روش رمزگذاری (امنیتی)</value>
</data> </data>
<data name="TbSNI" xml:space="preserve"> <data name="TbSNI" xml:space="preserve">
<value>SNI</value> <value>SNI</value>
@@ -635,7 +635,7 @@
<value>TLS</value> <value>TLS</value>
</data> </data>
<data name="TipNetwork" xml:space="preserve"> <data name="TipNetwork" xml:space="preserve">
<value>*Default value tcp</value> <value>*مقدار پیش فرض tcp</value>
</data> </data>
<data name="TbCoreType" xml:space="preserve"> <data name="TbCoreType" xml:space="preserve">
<value>نوع هسته</value> <value>نوع هسته</value>
@@ -644,7 +644,7 @@
<value>جریان</value> <value>جریان</value>
</data> </data>
<data name="TbGUID" xml:space="preserve"> <data name="TbGUID" xml:space="preserve">
<value>Generate</value> <value>ساختن</value>
</data> </data>
<data name="TbId3" xml:space="preserve"> <data name="TbId3" xml:space="preserve">
<value>رمزعبور</value> <value>رمزعبور</value>
@@ -668,10 +668,10 @@
<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 Xray/sing-box(Tun) to provide functions such as speed display</value> <value>* پس از تنظیم این مقدار، یک سرویس جوراب با استفاده از Xray/sing-box (Tun) برای ارائه عملکردهایی مانند نمایش سرعت شروع می شود.</value>
</data> </data>
<data name="TbBrowse" xml:space="preserve"> <data name="TbBrowse" xml:space="preserve">
<value>Browse</value> <value>مرور کردن</value>
</data> </data>
<data name="TbEdit" xml:space="preserve"> <data name="TbEdit" xml:space="preserve">
<value>ویرایش</value> <value>ویرایش</value>
@@ -683,7 +683,7 @@
<value>اتصالات از LAN را مجاز کنید</value> <value>اتصالات از LAN را مجاز کنید</value>
</data> </data>
<data name="TbSettingsAutoHideStartup" xml:space="preserve"> <data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>Auto hide startup</value> <value>راه اندازی مخفی کردن خودکار</value>
</data> </data>
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve"> <data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>فاصله به روز رسانی خودکار و Geo (ساعت)</value> <value>فاصله به روز رسانی خودکار و Geo (ساعت)</value>
@@ -692,7 +692,7 @@
<value>هسته: تنظیمات اولیه</value> <value>هسته: تنظیمات اولیه</value>
</data> </data>
<data name="TbSettingsCoreDns" xml:space="preserve"> <data name="TbSettingsCoreDns" xml:space="preserve">
<value>V2ray DNS settings</value> <value>تنظیمات V2ray DNS</value>
</data> </data>
<data name="TbSettingsCoreKcp" xml:space="preserve"> <data name="TbSettingsCoreKcp" xml:space="preserve">
<value>هسته: تنظیمات KCP</value> <value>هسته: تنظیمات KCP</value>
@@ -701,7 +701,7 @@
<value>تنظیمات CoreType</value> <value>تنظیمات CoreType</value>
</data> </data>
<data name="TbSettingsDefAllowInsecure" xml:space="preserve"> <data name="TbSettingsDefAllowInsecure" xml:space="preserve">
<value>اجازه ناامن</value> <value>اعطای مجوز ناامن</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Freedom" xml:space="preserve">
<value>Outbound Freedom domainStrategy</value> <value>Outbound Freedom domainStrategy</value>
@@ -716,7 +716,7 @@
<value>استثنا</value> <value>استثنا</value>
</data> </data>
<data name="TbSettingsExceptionTip" xml:space="preserve"> <data name="TbSettingsExceptionTip" xml:space="preserve">
<value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value> <value>استثنا: از سرور پروکسی برای آدرس هایی که با شروع می شوند استفاده نکنید، از نقطه ویرگول (;) استفاده کنید.</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve"> <data name="TbSettingsHttpPort" xml:space="preserve">
<value>پورت Http</value> <value>پورت Http</value>
@@ -725,7 +725,7 @@
<value>هنگام به‌روزرسانی هسته، فایل‌های Geo را نادیده بگیرید</value> <value>هنگام به‌روزرسانی هسته، فایل‌های Geo را نادیده بگیرید</value>
</data> </data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve"> <data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>Keep older when deduplication</value> <value>هنگام کپی برداری، نگه داری قدیمی تر ها</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>ثبت گزارش های محلی</value> <value>ثبت گزارش های محلی</value>
@@ -734,25 +734,25 @@
<value>سطح ثبت رویداد</value> <value>سطح ثبت رویداد</value>
</data> </data>
<data name="TbSettingsMuxEnabled" xml:space="preserve"> <data name="TbSettingsMuxEnabled" xml:space="preserve">
<value>Turn on Mux Multiplexing</value> <value>فعال کردن Mux Multiplexing</value>
</data> </data>
<data name="TbSettingsN" xml:space="preserve"> <data name="TbSettingsN" xml:space="preserve">
<value>تنظیمات v2rayN</value> <value>تنظیمات v2rayN</value>
</data> </data>
<data name="TbSettingsPass" xml:space="preserve"> <data name="TbSettingsPass" xml:space="preserve">
<value>Auth pass</value> <value>مجوز احراز هویت</value>
</data> </data>
<data name="TbSettingsRemoteDNS" xml:space="preserve"> <data name="TbSettingsRemoteDNS" xml:space="preserve">
<value>سفارشی DNS (multiple, separated by commas (,))</value> <value>سفارشی DNS (multiple, separated by commas (,))</value>
</data> </data>
<data name="TbSettingsSetUWP" xml:space="preserve"> <data name="TbSettingsSetUWP" xml:space="preserve">
<value>Set Win10 UWP Loopback</value> <value>تنظیم کردن Win10 UWP Loopback</value>
</data> </data>
<data name="TbSettingsSniffingEnabled" xml:space="preserve"> <data name="TbSettingsSniffingEnabled" xml:space="preserve">
<value>Turn on Sniffing</value> <value>فعال کردن Sniffing</value>
</data> </data>
<data name="TbSettingsSocksPort" xml:space="preserve"> <data name="TbSettingsSocksPort" xml:space="preserve">
<value>ساکس Port</value> <value>پورت Mixed</value>
</data> </data>
<data name="TbSettingsStartBoot" xml:space="preserve"> <data name="TbSettingsStartBoot" xml:space="preserve">
<value>درهنگام راه ائدازی شروع شود</value> <value>درهنگام راه ائدازی شروع شود</value>
@@ -761,22 +761,22 @@
<value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value> <value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsSubConvert" xml:space="preserve"> <data name="TbSettingsSubConvert" xml:space="preserve">
<value>Subscription conversion Url</value> <value>آدرس اینترنتی تبدیل اشتراک</value>
</data> </data>
<data name="TbSettingsSystemproxy" xml:space="preserve"> <data name="TbSettingsSystemproxy" xml:space="preserve">
<value>تنظیمات پراکسی سیستم</value> <value>تنظیمات پراکسی سیستم</value>
</data> </data>
<data name="TbSettingsTLS13" xml:space="preserve"> <data name="TbSettingsTLS13" xml:space="preserve">
<value>Enable Security Protocol TLS v1.3 (subscription/update)</value> <value>فعال کردن پروتکل امنیتی TLS نسخه 1.3 (اشتراک/به‌روزرسانی)</value>
</data> </data>
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve"> <data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
<value>Tray right-click menu servers display limit</value> <value>محدودیت نمایش سرورهای منوی سینی کلیک راست</value>
</data> </data>
<data name="TbSettingsUdpEnabled" xml:space="preserve"> <data name="TbSettingsUdpEnabled" xml:space="preserve">
<value>UDP را فعال شود</value> <value>فعال سازی UDP</value>
</data> </data>
<data name="TbSettingsUser" xml:space="preserve"> <data name="TbSettingsUser" xml:space="preserve">
<value>Auth user</value> <value>تایید کاربر</value>
</data> </data>
<data name="TbClearSystemProxy" xml:space="preserve"> <data name="TbClearSystemProxy" xml:space="preserve">
<value>پاک کردن پروکسی سیستم</value> <value>پاک کردن پروکسی سیستم</value>
@@ -821,16 +821,16 @@
<value>پایین (D)</value> <value>پایین (D)</value>
</data> </data>
<data name="menuMoveTop" xml:space="preserve"> <data name="menuMoveTop" xml:space="preserve">
<value>Move to top (T)</value> <value>حرکت به بالا (T)</value>
</data> </data>
<data name="menuMoveUp" xml:space="preserve"> <data name="menuMoveUp" xml:space="preserve">
<value>Up (U)</value> <value>بالا (U)</value>
</data> </data>
<data name="MsgFilterTitle" xml:space="preserve"> <data name="MsgFilterTitle" xml:space="preserve">
<value>Filter, support regular</value> <value>فیلتر، پشتیبانی منظم</value>
</data> </data>
<data name="menuWebsiteItem" xml:space="preserve"> <data name="menuWebsiteItem" xml:space="preserve">
<value>{0} Website</value> <value>{0} وب سایت</value>
</data> </data>
<data name="menuRoutingAdvanced" xml:space="preserve"> <data name="menuRoutingAdvanced" xml:space="preserve">
<value>عملکرد پیشرفته</value> <value>عملکرد پیشرفته</value>
@@ -845,13 +845,7 @@
<value>حذف انتخاب شده</value> <value>حذف انتخاب شده</value>
</data> </data>
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule</value> <value>تنظیم کردن به عنوان قانون فعال</value>
</data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>عملکرد پایه</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>واردات قوانین اساسی</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>تطبیق دامنه</value> <value>تطبیق دامنه</value>
@@ -863,19 +857,19 @@
<value>فعال کردن عملکرد پیشرفته</value> <value>فعال کردن عملکرد پیشرفته</value>
</data> </data>
<data name="TbRoutingTabBlock" xml:space="preserve"> <data name="TbRoutingTabBlock" xml:space="preserve">
<value>3.Block Domain or IP</value> <value>3. مسدود کردن دامنه یا آیپی</value>
</data> </data>
<data name="TbRoutingTabDirect" xml:space="preserve"> <data name="TbRoutingTabDirect" xml:space="preserve">
<value>2.Direct Domain or IP</value> <value>2. دایرکت کردن دامنه یا IP</value>
</data> </data>
<data name="TbRoutingTabProxy" xml:space="preserve"> <data name="TbRoutingTabProxy" xml:space="preserve">
<value>1.Proxy Domain or IP</value> <value>1. پروکسی کردن دامنه یا IP</value>
</data> </data>
<data name="TbRoutingTabRuleList" xml:space="preserve"> <data name="TbRoutingTabRuleList" xml:space="preserve">
<value>لیست مجموعه قوانین از پیش تعریف شده</value> <value>لیست مجموعه قوانین از پیش تعریف شده</value>
</data> </data>
<data name="TbRoutingTips" xml:space="preserve"> <data name="TbRoutingTips" xml:space="preserve">
<value>*Set the rules, separated by commas (,); The comma in the regular is replaced by &lt;COMMA&gt;</value> <value>*قوانین را تنظیم کنید که با کاما از هم جدا شده اند (,); کاما در حالت عادی با &lt;COMMA&gt;</value>
</data> </data>
<data name="menuImportRulesFromClipboard" xml:space="preserve"> <data name="menuImportRulesFromClipboard" xml:space="preserve">
<value>وارد کردن قوانین از کلیپ بورد</value> <value>وارد کردن قوانین از کلیپ بورد</value>
@@ -884,7 +878,7 @@
<value>وارد کردن قوانین از فایل</value> <value>وارد کردن قوانین از فایل</value>
</data> </data>
<data name="menuImportRulesFromUrl" xml:space="preserve"> <data name="menuImportRulesFromUrl" xml:space="preserve">
<value>وارد کردن قوانین از Sub Url</value> <value>وارد کردن قوانین از آدرس اینترنتی Sub</value>
</data> </data>
<data name="menuRoutingRuleSetting" xml:space="preserve"> <data name="menuRoutingRuleSetting" xml:space="preserve">
<value>تنظیم قانون</value> <value>تنظیم قانون</value>
@@ -908,7 +902,7 @@
<value>دامنه و آی پی در هنگام ذخیره به طور خودکار مرتب می شوند</value> <value>دامنه و آی پی در هنگام ذخیره به طور خودکار مرتب می شوند</value>
</data> </data>
<data name="TbRuleobjectDoc" xml:space="preserve"> <data name="TbRuleobjectDoc" xml:space="preserve">
<value>Ruleobject Doc</value> <value>مستندات شی قانون</value>
</data> </data>
<data name="TbDnsObjectDoc" xml:space="preserve"> <data name="TbDnsObjectDoc" xml:space="preserve">
<value>پشتیبانی از DnsObject</value> <value>پشتیبانی از DnsObject</value>
@@ -926,16 +920,16 @@
<value>فقط مسیر</value> <value>فقط مسیر</value>
</data> </data>
<data name="TbSettingsNotProxyLocalAddress" xml:space="preserve"> <data name="TbSettingsNotProxyLocalAddress" xml:space="preserve">
<value>يەرلىك (Intranet) ئادرېسلارغا ۋاكالەتچى مۇلازىمېتىر ئىشلەتمەڭ</value> <value>از سرورهای پروکسی برای آدرس های محلی (اینترانت) استفاده نکنید</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>One-click test Latency and speed (Ctrl+E)</value> <value>تاخیر و سرعت تست با یک کلیک (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>تاخیر (میلی‌ثانیه)</value> <value>تاخیر (میلی‌ثانیه)</value>
</data> </data>
<data name="LvTestSpeed" xml:space="preserve"> <data name="LvTestSpeed" xml:space="preserve">
<value>Speed(M/s)</value> <value>سرعت (M/s)</value>
</data> </data>
<data name="FailedToRunCore" xml:space="preserve"> <data name="FailedToRunCore" xml:space="preserve">
<value>Core اجرا نشد، لطفاً گزارش را ببینید</value> <value>Core اجرا نشد، لطفاً گزارش را ببینید</value>
@@ -950,7 +944,7 @@
<value>پیکربندی قدیمی guiNConfig را وارد شود</value> <value>پیکربندی قدیمی guiNConfig را وارد شود</value>
</data> </data>
<data name="TbEnableTunAs" xml:space="preserve"> <data name="TbEnableTunAs" xml:space="preserve">
<value>Tun را فعال شود</value> <value>فعال سازی Tun</value>
</data> </data>
<data name="TbSettingsNewPort4LAN" xml:space="preserve"> <data name="TbSettingsNewPort4LAN" xml:space="preserve">
<value>پورت جدید برای LAN</value> <value>پورت جدید برای LAN</value>
@@ -962,10 +956,10 @@
<value>User-Agent</value> <value>User-Agent</value>
</data> </data>
<data name="TbSettingsDefUserAgentTips" xml:space="preserve"> <data name="TbSettingsDefUserAgentTips" xml:space="preserve">
<value>This parameter is valid only for tcp/http and ws</value> <value>این پارامتر فقط برای tcp/http و ws معتبر است</value>
</data> </data>
<data name="TbSettingsEnableHWA" xml:space="preserve"> <data name="TbSettingsEnableHWA" xml:space="preserve">
<value>فعال‌سازی شتاب‌دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد)</value> <value>فعال‌ سازی شتاب‌ دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve"> <data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value> <value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
@@ -974,7 +968,7 @@
<value>مرتب سازی</value> <value>مرتب سازی</value>
</data> </data>
<data name="TbSortingDefault" xml:space="preserve"> <data name="TbSortingDefault" xml:space="preserve">
<value>Default</value> <value>پیش فرض</value>
</data> </data>
<data name="TbSortingDelay" xml:space="preserve"> <data name="TbSortingDelay" xml:space="preserve">
<value>تاخیر</value> <value>تاخیر</value>
@@ -1013,10 +1007,10 @@
<value>نوع قانون</value> <value>نوع قانون</value>
</data> </data>
<data name="menuModeDirect" xml:space="preserve"> <data name="menuModeDirect" xml:space="preserve">
<value>Direct</value> <value>مستقیم</value>
</data> </data>
<data name="menuModeGlobal" xml:space="preserve"> <data name="menuModeGlobal" xml:space="preserve">
<value>Global</value> <value>جهانی</value>
</data> </data>
<data name="menuModeNothing" xml:space="preserve"> <data name="menuModeNothing" xml:space="preserve">
<value>تغییر نده</value> <value>تغییر نده</value>
@@ -1025,12 +1019,387 @@
<value>قانون</value> <value>قانون</value>
</data> </data>
<data name="menuProxiesDelaytest" xml:space="preserve"> <data name="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value> <value>تست تأخیر</value>
</data> </data>
<data name="menuProxiesDelaytestPart" xml:space="preserve"> <data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>Part Node Latency Test</value> <value>تست تاخیر قسمت گره (نقطه اتصال)</value>
</data> </data>
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value> <value>انتخاب گره فعال (Enter)</value>
</data> </data>
</root> <data name="menuRemoteBackup" xml:space="preserve">
<value>پشتیبان گیری از راه دور (WebDAV)</value>
</data>
<data name="menuRemoteRestore" xml:space="preserve">
<value>بازیابی از راه دور (WebDAV)</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>استراتژی دامنه پیش فرض برای خروجی</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>کمترین تأخیر چند سروره</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>جهت چیدمان اصلی (نیاز به راه اندازی مجدد)</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>تعادل بار چند سروره</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>آدرس DNS خروجی</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>تنظیم خودکار عرض ستون</value>
</data>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>صادر کردن پیوندهای اشتراک گذاری کدگذاری شده با Base64 به کلیپ بورد</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>صادر کردن سرور انتخاب شده برای پیکربندی کامل به کلیپ بورد</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>نمایش یا پنهان کردن پنجره اصلی</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>شما در حال حاضر در حال اجرای یک بسته مستقل هستید، لطفاً فایل SelfContained.7z را به صورت دستی دانلود کنید تا آن را از حالت فشرده خارج کرده و بازنویسی کنید!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>پیکربندی سفارشی ساکس پورت</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>پشتیبان گیری و بازیابی</value>
</data>
<data name="menuLocalBackup" xml:space="preserve">
<value>پشتیبان گیری به محلی</value>
</data>
<data name="menuLocalRestore" xml:space="preserve">
<value>بازیابی از محلی</value>
</data>
<data name="menuLocalBackupAndRestore" xml:space="preserve">
<value>محلی</value>
</data>
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>از راه دور (WebDAV)</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>آدرس اینترنتی WebDav</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>نام کاربری WebDav</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>پسورد WebDav</value>
</data>
<data name="LvWebDavCheck" xml:space="preserve">
<value>چک کردن WebDav</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>نام پوشه راه دور (اختیاری)</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>فایل پشتیبان نامعتبر است</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
<data name="TipActiveServer" xml:space="preserve">
<value>فعال سازی</value>
</data>
<data name="menuStorageUI" xml:space="preserve">
<value>ذخیره طرح رابط</value>
</data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>منبع فایل های جغرافیایی (اختیاری)</value>
</data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>منبع فایل های مجموعه قوانین sing-box (اختیاری)</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>برنامه ارتقا وجود ندارد</value>
</data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>منبع قوانین مسیریابی (اختیاری)</value>
</data>
<data name="menuRegionalPresets" xml:space="preserve">
<value>تنظیمات از پیش تعیین شده منطقه ای</value>
</data>
<data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>پیش فرض</value>
</data>
<data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>روسیه</value>
</data>
<data name="menuRegionalPresetsIran" xml:space="preserve">
<value>ایران</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>کاربران در منطقه چین می توانند این مورد را نادیده بگیرند</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve">
<value>اسکن کردن QRcode موجود در تصویر</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>آدرس نامعتبر (آدرس اینترنتی)</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>لطفاً از آدرس اشتراک پروتکل HTTP ناامن استفاده نکنید</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>فونت را روی سیستم نصب کنید و تنظیمات را مجددا راه اندازی کنید</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>آیا مطمئن هستید که خارج می شوید؟</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>یادداشت ملاحظات</value>
</data>
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>فعال کردن ورود به فایل</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>به روز رسانی ها فعال نیستند، از این اشتراک رد شوید</value>
</data>
<data name="menuRebootAsAdmin" xml:space="preserve">
<value>به عنوان مدیر راه اندازی مجدد</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>نشانی‌های وب بیشتر که با کاما از هم جدا شده‌اند. تبدیل اشتراک نامعتبر خواهد بود</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvAutoUpdateInterval" xml:space="preserve">
<value>فاصله به روز رسانی خودکار (دقیقه)</value>
</data>
<data name="LvConvertTarget" xml:space="preserve">
<value>تبدیل نوع هدف</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>اگر نیازی به تبدیل نیست، لطفاً خالی بگذارید</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>لطفاً در صورت قطع غیرعادی آن را خاموش کنید</value>
</data>
<data name="menuDNSSetting" xml:space="preserve">
<value>تنظیمات DNS</value>
</data>
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
<value>لطفا ساختار DNS را پر کنید، برای مشاهده سند کلیک کنید</value>
</data>
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
<value>برای وارد کردن تنظیمات پیش‌فرض DNS کلیک کنید</value>
</data>
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
<value>استراتژی دامنه sing-box</value>
</data>
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>پروتکل sing-box Mux</value>
</data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>نام کامل فرانید (حالت Tun)</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>دامنه</value>
</data>
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
<value>تنظیمات DNS sing-box</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>در انتظار آزمایش (برای پایان دادن به ESC فشار دهید)...</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve">
<value>انتقال به گروه</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>فعال کردن مرتب سازی با کشیدن سرور (نیاز به راه اندازی مجدد)</value>
</data>
<data name="TbAutoRefresh" xml:space="preserve">
<value>بازخوانی خودکار</value>
</data>
<data name="SpeedtestingSkip" xml:space="preserve">
<value>رد شدن از آزمون</value>
</data>
<data name="menuEditServer" xml:space="preserve">
<value>ویرایش سرور (Ctrl+D)</value>
</data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>روی server make active دوبار کلیک کنید</value>
</data>
<data name="SpeedtestingCompleted" xml:space="preserve">
<value>تست تکمیل شد</value>
</data>
<data name="TbSettingsDefFingerprint" xml:space="preserve">
<value>اثر انگشت tls پیش فرض</value>
</data>
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
<value>FontFamily (نیاز به راه اندازی مجدد)</value>
</data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>فایل TTF/TTC فونت را در دایرکتوری guiFonts کپی کنید، تنظیمات را مجددا راه اندازی کنید</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>پورت Pac = +3; پورت Xray API = +4; پورت mihomo API = +5;</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>این را با امتیازات ادمین تنظیم کنید، پس از راه اندازی، امتیازات مدیر را دریافت کنید</value>
</data>
<data name="TbSettingsFontSize" xml:space="preserve">
<value>اندازه فونت</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>یمقدار تاخیر تست سرعت منفرد</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>/آدرس اینترنتی SpeedTest</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>بالا و پایین حرکت کنید</value>
</data>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] server</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>حداکتر پهنای باند هیستریا (آپلود/دانلود)</value>
</data>
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
<value>دنبال کردن تم سیستم</value>
</data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>افزودن سرور [TUIC]</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>اشتراک در حال به‌روزرسانی، فقط مشخص کنید که ملاحظاتی وجود دارد</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>تازه سازی پروکسی ها</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>شبکه</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>نوع</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>افزودن سرور [HTTP]</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>آدرس اینترنتی تست پینگ سرعت</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>از Xray استفاده کنید و حالت non-Tun را فعال کنید، که با پراکسی قبلی گروه در تضاد است</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>سفارش سازی مجموعه قوانین از sing box</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>عملکرد موفقیت آمیز بود، روی منوی تنظیمات کلیک کنید تا برنامه راه اندازی مجدد شود.</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>باز کردن محل ذخیره سازی</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>Host</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>استفاده کردن از System Hosts</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>فعال کردن فرگمنت</value>
</data>
<data name="TbAutoScrollToEnd" xml:space="preserve">
<value>خودکار ScrollToEnd</value>
</data>
<data name="SpeedtestingStop" xml:space="preserve">
<value>پایان تست...</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>پسورد obfs</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>کنترل تراکم</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>آدرس (IP, IPv6)</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>کلید خصوصی</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>افزودن سرور [WireGuard]</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>فعال سازی آدرس IPv6</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>فعال سازی additional Inbound</value>
</data>
<data name="LvPrevProfileTip" xml:space="preserve">
<value>لطفاً مطمئن شوید که ملاحظات وجود دارد و منحصر به فرد است</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="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>رمز عبور sudo سیستم</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>رمز عبور رمزگذاری شده و فقط در فایل های محلی ذخیره می شود.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>لطفا این برنامه را با sudo اجرا نکنید</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*حالت xhttp</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>جیسون خام XHTTP Extra, فرمت: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>هنگام بستن پنجره در سینی پنهان شوید</value>
</data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
<value>تعداد در هر زمان برای دسته خودکار در طول تست سرعت (حداکثر 1000)</value>
</data>
<data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>استثنا:از سرور پروکسی برای آدرس ها، با کاما (،) استفاده نکنید</value>
</data>
<data name="TbSettingsDestOverride" xml:space="preserve">
<value>نوع Sniffing</value>
</data>
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
<value>فعال کردن دومین پورت ترکیبی</value>
</data>
<data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks:پورت محلی، socks2: پورت دوم محلی، socks3: پورت LAN</value>
</data>
</root>

File diff suppressed because it is too large Load Diff

View File

@@ -302,7 +302,7 @@
<value>Scan import the shared link 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 delay : {0} ms, {1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>Operation success</value> <value>Operation success</value>
@@ -344,7 +344,7 @@
<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/httpupgrade/splithttp path</value> <value>*ws/httpupgrade/xhttp path</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>*h2 path</value>
@@ -359,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/httpupgrade/splithttp host</value> <value>*ws/httpupgrade/xhttp 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>
@@ -755,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>Mixed 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>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule(Enter)</value> <value>Set as active rule(Enter)</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>Basic Function</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>Import Basic Rules</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>Domain Matcher</value> <value>Domain Matcher</value>
</data> </data>
@@ -998,7 +992,7 @@
<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 = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value> <value>Pac port = +3; Xray API port = +4; mihomo API port = +5;</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>
@@ -1348,6 +1342,9 @@
<data name="menuRegionalPresetsRussia" xml:space="preserve"> <data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>Russia</value> <value>Russia</value>
</data> </data>
<data name="menuRegionalPresetsIran" xml:space="preserve">
<value>Iran</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve"> <data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>Users in China region can ignore this item</value> <value>Users in China region can ignore this item</value>
</data> </data>
@@ -1363,4 +1360,46 @@
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value> <value>Install the font to the system and restart the settings</value>
</data> </data>
<data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>System sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
<value>Number per time for auto batch during speedtest(max 1000)</value>
</data>
<data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value>
</data>
<data name="TbSettingsDestOverride" xml:space="preserve">
<value>Sniffing type</value>
</data>
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
<value>Enable second mixed port</value>
</data>
<data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
</data>
</root> </root>

View File

@@ -302,7 +302,7 @@
<value>Сканирование URL-адреса импорта успешна.</value> <value>Сканирование URL-адреса импорта успешна.</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>Задержка текущего сервера: {0} мс</value> <value>Задержка текущего сервера: {0} мс, {1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>Операция успешна</value> <value>Операция успешна</value>
@@ -761,7 +761,7 @@
<value>Включить сниффинг</value> <value>Включить сниффинг</value>
</data> </data>
<data name="TbSettingsSocksPort" xml:space="preserve"> <data name="TbSettingsSocksPort" xml:space="preserve">
<value>Порт Socks</value> <value>Mixed Port</value>
</data> </data>
<data name="TbSettingsStartBoot" xml:space="preserve"> <data name="TbSettingsStartBoot" xml:space="preserve">
<value>Автозапуск</value> <value>Автозапуск</value>
@@ -856,12 +856,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Установить как активное правило</value> <value>Установить как активное правило</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>Основные функции</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>Импорт основных правил</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>Сопоставитель доменов</value> <value>Сопоставитель доменов</value>
</data> </data>
@@ -1045,7 +1039,367 @@
<data name="menuRegionalPresetsRussia" xml:space="preserve"> <data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>Россия</value> <value>Россия</value>
</data> </data>
<data name="menuRegionalPresetsIran" xml:space="preserve">
<value>Иран</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve"> <data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>Используйте Настройки -> Региональные пресеты вместо изменения этого поля</value> <value>Используйте Настройки -&gt; Региональные пресеты вместо изменения этого поля</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</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="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</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="TbPath7" xml:space="preserve">
<value>obfs password</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</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="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [WireGuard] server</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="TbSortingDelay" xml:space="preserve">
<value>Delay</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Enable additional Inbound</value>
</data>
<data name="LvPrevProfileTip" xml:space="preserve">
<value>Please make sure the remarks exists and is unique</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected server for complete configuration to clipboard</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound DNS address</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="TbSortingDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>Sorting</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</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="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>Enable cache file for sing-box (ruleset files)</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="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</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="menuModeRule" xml:space="preserve">
<value>Rule</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP] server</value>
</data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] server</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="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</value>
</data>
<data name="LvWebDavCheck" xml:space="preserve">
<value>WebDav Check</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Full process name (Tun mode)</value>
</data>
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux Protocol</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>Invalid backup file</value>
</data>
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
<value>sing-box domain strategy</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
<value>Click to import default DNS config</value>
</data>
<data name="TipActiveServer" xml:space="preserve">
<value>Active</value>
</data>
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
<value>Please fill in DNS Structure, Click to view the document</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>Please leave blank if no conversion is required</value>
</data>
<data name="LvConvertTarget" xml:space="preserve">
<value>Convert target type</value>
</data>
<data name="menuStorageUI" xml:space="preserve">
<value>Save Interface Layout</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>Updates are not enabled, skip this subscription</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>UpgradeApp does not exist</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve">
<value>Scan QR code in the image</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing (press ESC to terminate)...</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>Invalid address (Url)</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>Please do not use the insecure HTTP protocol subscription address</value>
</data>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>Pac port = +3; Xray API port = +4; mihomo API port = +5;</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] server</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>WebDav Password</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>Remote folder name (optional)</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>Download Speed</value>
</data>
<data name="menuRemoteRestore" xml:space="preserve">
<value>Restore from remote (WebDAV)</value>
</data>
<data name="menuRemoteBackup" xml:space="preserve">
<value>Backup to remote (WebDAV)</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>WebDav User Name</value>
</data>
<data name="menuLocalRestore" xml:space="preserve">
<value>Restore from local</value>
</data>
<data name="menuLocalBackup" xml:space="preserve">
<value>Backup to local</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>Use System Hosts</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>Backup and Restore</value>
</data>
<data name="menuLocalBackupAndRestore" xml:space="preserve">
<value>Local</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Dw)</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav Url</value>
</data>
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>Remote (WebDAV)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>System sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
<value>Number per time for auto batch during speedtest(max 1000)</value>
</data>
<data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value>
</data>
<data name="TbSettingsDestOverride" xml:space="preserve">
<value>Sniffing type</value>
</data>
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
<value>Enable second mixed port</value>
</data>
<data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks: local port, socks2: second local port, socks3: LAN port</value>
</data> </data>
</root> </root>

View File

@@ -302,7 +302,7 @@
<value>扫描导入分享链接成功</value> <value>扫描导入分享链接成功</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>当前服务的真连接延迟: {0} ms</value> <value>当前延迟: {0} ms{1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value> <value>操作成功</value>
@@ -344,7 +344,7 @@
<value>请填写正确的自定义DNS</value> <value>请填写正确的自定义DNS</value>
</data> </data>
<data name="TransportPathTip1" xml:space="preserve"> <data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value> <value>*ws/httpupgrade/xhttp path</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>*h2 path</value>
@@ -359,7 +359,7 @@
<value>*http host中间逗号(,)分隔</value> <value>*http host中间逗号(,)分隔</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value> <value>*ws/httpupgrade/xhttp host</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中间逗号(,)分隔</value> <value>*h2 host中间逗号(,)分隔</value>
@@ -755,7 +755,7 @@
<value>开启流量探测</value> <value>开启流量探测</value>
</data> </data>
<data name="TbSettingsSocksPort" xml:space="preserve"> <data name="TbSettingsSocksPort" xml:space="preserve">
<value>本地socks监听端口</value> <value>本地混合监听端口</value>
</data> </data>
<data name="TbSettingsStartBoot" xml:space="preserve"> <data name="TbSettingsStartBoot" xml:space="preserve">
<value>开机启动(可能会不成功)</value> <value>开机启动(可能会不成功)</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>设为活动规则 (Enter)</value> <value>设为活动规则 (Enter)</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>基础功能</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>一键导入基础规则</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配算法</value> <value>域名匹配算法</value>
</data> </data>
@@ -998,7 +992,7 @@
<value>拷贝字体TTF/TTC文件到目录guiFonts重启设置</value> <value>拷贝字体TTF/TTC文件到目录guiFonts重启设置</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve"> <data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value> <value>Pac端口= +3Xray API端口= +4mihomo API端口= +5</value>
</data> </data>
<data name="TbSettingsStartBootTip" xml:space="preserve"> <data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理员权限设置此项,在启动后获得管理员权限</value> <value>以管理员权限设置此项,在启动后获得管理员权限</value>
@@ -1271,7 +1265,7 @@
<value>显示或隐藏主界面</value> <value>显示或隐藏主界面</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve"> <data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value> <value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value>
</data> </data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自定义配置的Socks端口</value> <value>自定义配置的Socks端口</value>
@@ -1348,6 +1342,9 @@
<data name="menuRegionalPresetsRussia" xml:space="preserve"> <data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>俄罗斯</value> <value>俄罗斯</value>
</data> </data>
<data name="menuRegionalPresetsIran" xml:space="preserve">
<value>伊朗</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve"> <data name="menuAddServerViaImage" xml:space="preserve">
<value>扫描图片中的二维码</value> <value>扫描图片中的二维码</value>
</data> </data>
@@ -1360,4 +1357,46 @@
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安装字体到系统中,重启设置</value> <value>安装字体到系统中,重启设置</value>
</data> </data>
<data name="menuExitTips" xml:space="preserve">
<value>是否确定退出?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>备注备忘</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>系统的sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在Tun模式设置中设置sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>请不要用sudo运行本app</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>关闭窗口时隐藏至托盘</value>
</data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
<value>测试时自动分批的每批数量最大1000</value>
</data>
<data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>例外. 对于下列地址不使用代理配置文件:使用逗号(,)分隔</value>
</data>
<data name="TbSettingsDestOverride" xml:space="preserve">
<value>流量探测类型</value>
</data>
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
<value>开启第二个本地监听端口</value>
</data>
<data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks本地端口socks2第二个本地端口socks3局域网端口</value>
</data>
</root> </root>

View File

@@ -127,7 +127,7 @@
<value>設定格式不正確</value> <value>設定格式不正確</value>
</data> </data>
<data name="CustomServerTips" xml:space="preserve"> <data name="CustomServerTips" xml:space="preserve">
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value> <value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
</data> </data>
<data name="Downloading" xml:space="preserve"> <data name="Downloading" xml:space="preserve">
<value>下載開始...</value> <value>下載開始...</value>
@@ -157,7 +157,7 @@
<value>請填寫正確格式伺服器埠</value> <value>請填寫正確格式伺服器埠</value>
</data> </data>
<data name="FillLocalListeningPort" xml:space="preserve"> <data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機聽埠</value> <value>請填寫本機聽埠</value>
</data> </data>
<data name="FillPassword" xml:space="preserve"> <data name="FillPassword" xml:space="preserve">
<value>請填寫密碼</value> <value>請填寫密碼</value>
@@ -301,7 +301,7 @@
<value>掃描匯入分享链接成功</value> <value>掃描匯入分享链接成功</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>目前服務的真連接延遲: {0} ms</value> <value>目前延遲: {0} ms{1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value> <value>操作成功</value>
@@ -343,7 +343,7 @@
<value>請填寫正確的自訂DNS</value> <value>請填寫正確的自訂DNS</value>
</data> </data>
<data name="TransportPathTip1" xml:space="preserve"> <data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value> <value>*ws/httpupgrade/xhttp path</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>*h2 path</value>
@@ -358,7 +358,7 @@
<value>*http host中間逗號(,)分隔</value> <value>*http host中間逗號(,)分隔</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value> <value>*ws/httpupgrade/xhttp host</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中間逗號(,)分隔</value> <value>*h2 host中間逗號(,)分隔</value>
@@ -511,7 +511,7 @@
<value>清除所有服務統計資料</value> <value>清除所有服務統計資料</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>測試伺服器真連延遲(多選) (Ctrl+R)</value> <value>測試伺服器真連延遲(多選) (Ctrl+R)</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>按測試結果排序</value> <value>按測試結果排序</value>
@@ -683,7 +683,7 @@
<value>進階代理設定, 協定選擇(可選)</value> <value>進階代理設定, 協定選擇(可選)</value>
</data> </data>
<data name="TbSettingsAllowLAN" xml:space="preserve"> <data name="TbSettingsAllowLAN" xml:space="preserve">
<value>允許來自區域網路的連</value> <value>允許來自區域網路的連</value>
</data> </data>
<data name="TbSettingsAutoHideStartup" xml:space="preserve"> <data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>啟動後隱藏視窗</value> <value>啟動後隱藏視窗</value>
@@ -722,7 +722,7 @@
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value> <value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve"> <data name="TbSettingsHttpPort" xml:space="preserve">
<value>本機HTTP聽埠</value> <value>本機HTTP聽埠</value>
</data> </data>
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve"> <data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core時忽略Geo檔案</value> <value>更新Core時忽略Geo檔案</value>
@@ -755,7 +755,7 @@
<value>開啟流量探測</value> <value>開啟流量探測</value>
</data> </data>
<data name="TbSettingsSocksPort" xml:space="preserve"> <data name="TbSettingsSocksPort" xml:space="preserve">
<value>本機SOCKS監聽埠</value> <value>本機混合偵聽埠</value>
</data> </data>
<data name="TbSettingsStartBoot" xml:space="preserve"> <data name="TbSettingsStartBoot" xml:space="preserve">
<value>開機啟動(可能會不成功)</value> <value>開機啟動(可能會不成功)</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>設為活動規則 (Enter)</value> <value>設為活動規則 (Enter)</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>基礎功能</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>一鍵匯入基礎規則</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配演算法</value> <value>域名匹配演算法</value>
</data> </data>
@@ -998,7 +992,7 @@
<value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value> <value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve"> <data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value> <value>Pac連接埠= +3Xray API連接埠= +4mihomo API連接埠= +5</value>
</data> </data>
<data name="TbSettingsStartBootTip" xml:space="preserve"> <data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value> <value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
@@ -1094,7 +1088,7 @@
<value>請確保別名存在並且唯一</value> <value>請確保別名存在並且唯一</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve"> <data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>啟用額外監聽端口</value> <value>啟用額外偵聽連接埠</value>
</data> </data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>啟用IPv6</value> <value>啟用IPv6</value>
@@ -1106,7 +1100,7 @@
<value>自动滚动到末尾</value> <value>自动滚动到末尾</value>
</data> </data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>真連測試址</value> <value>真連測試址</value>
</data> </data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve"> <data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>更新訂閱時只判斷別名是否存在</value> <value>更新訂閱時只判斷別名是否存在</value>
@@ -1151,10 +1145,10 @@
<value>顯示或隱藏主介面</value> <value>顯示或隱藏主介面</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve"> <data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value> <value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
</data> </data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂設定的Socks端口</value> <value>自訂設定的Socks連接埠</value>
</data> </data>
<data name="menuBackupAndRestore" xml:space="preserve"> <data name="menuBackupAndRestore" xml:space="preserve">
<value>備份和還原</value> <value>備份和還原</value>
@@ -1187,7 +1181,7 @@
<value>WebDav 密碼</value> <value>WebDav 密碼</value>
</data> </data>
<data name="LvWebDavUrl" xml:space="preserve"> <data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav 伺服器址</value> <value>WebDav 伺服器址</value>
</data> </data>
<data name="LvWebDavDirName" xml:space="preserve"> <data name="LvWebDavDirName" xml:space="preserve">
<value>遠端資料夾名稱(可選)</value> <value>遠端資料夾名稱(可選)</value>
@@ -1205,39 +1199,204 @@
<value>儲存介面佈局</value> <value>儲存介面佈局</value>
</data> </data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve"> <data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>Geo文件來源(可選)</value> <value>Geo檔案來源(可選)</value>
</data> </data>
<data name="UpgradeAppNotExistTip" xml:space="preserve"> <data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>升工具App不存在</value> <value>升工具App不存在</value>
</data> </data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve"> <data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>sing-box ruleset文件來源(可選)</value> <value>sing-box ruleset檔案來源(可選)</value>
</data> </data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve"> <data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>路由规则集来源(可)</value> <value>路由規則集來源(可)</value>
</data> </data>
<data name="TbSettingsChinaUserTip" xml:space="preserve"> <data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>中国区域用可忽略此</value> <value>中國區域用可忽略此</value>
</data> </data>
<data name="menuRegionalPresets" xml:space="preserve"> <data name="menuRegionalPresets" xml:space="preserve">
<value>区域预置设置</value> <value>區域預置設定</value>
</data> </data>
<data name="menuRegionalPresetsDefault" xml:space="preserve"> <data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>默认区域</value> <value>預設區域</value>
</data> </data>
<data name="menuRegionalPresetsRussia" xml:space="preserve"> <data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>俄羅斯</value> <value>俄羅斯</value>
</data> </data>
<data name="menuRegionalPresetsIran" xml:space="preserve">
<value>伊朗</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve"> <data name="menuAddServerViaImage" xml:space="preserve">
<value>掃描圖片中的二維碼</value> <value>掃描圖片中的二維碼</value>
</data> </data>
<data name="InvalidUrlTip" xml:space="preserve"> <data name="InvalidUrlTip" xml:space="preserve">
<value>址(Url)無效</value> <value>址(Url)無效</value>
</data> </data>
<data name="InsecureUrlProtocol" xml:space="preserve"> <data name="InsecureUrlProtocol" xml:space="preserve">
<value>請不要使用不安全的HTTP協定訂閱位址</value> <value>請不要使用不安全的HTTP協定訂閱位址</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安裝字到系統中,重新啟動設定</value> <value>安裝字到系統中,重新啟動設定</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>是否確定退出?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>備註備忘</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>擁塞控制算法</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>設為活動節點 (Enter)</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>重新整理</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>排序</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>延遲測試</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>規則</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>随原配置</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>全局</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>直連</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>規則模式</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>目前代理</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>關閉所有連線</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Outbound預設解析策略</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>關閉連線</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>上傳流量</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>上傳速度</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>類型</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>時間</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>網路</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>名稱</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>主機</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>下載流量</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>下載速度</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>延遲</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>預設</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>目前連線</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>多伺服器最低延遲 (多選)</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>目前部分節點延遲測試</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>多伺服器負載平衡 (多選)</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>添加[Hysteria2]伺服器</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria 最大頻寬(Up/Dw)</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>主界面佈局方向(需重啟)</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>添加[WireGuard]伺服器</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="TbSettingsUseSystemHosts" xml:space="preserve">
<value>使用系統hosts</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>路由鏈</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound域名解析位址</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>混淆密碼(obfs password)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>系統的sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在Tun模式設定中設定sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>請不要用sudo來運行本app</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>關閉視窗時隱藏至托盤</value>
</data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve">
<value>測試時自動分批的每批數量最大1000</value>
</data>
<data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>例外. 對於下列位址不使用代理設定檔:使用逗號(,)分隔</value>
</data>
<data name="TbSettingsDestOverride" xml:space="preserve">
<value>流量探測類型</value>
</data>
<data name="TbSettingsSecondLocalPortEnabled" xml:space="preserve">
<value>開啟第二個本機監聽埠</value>
</data>
<data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks本地端口socks2第二個本地端口socks3區域網路端口</value>
</data> </data>
</root> </root>

View File

@@ -6,6 +6,13 @@
"bittorrent" "bittorrent"
] ]
}, },
{
"remarks": "api.ip.sb",
"outboundTag": "proxy",
"domain": [
"api.ip.sb"
]
},
{ {
"remarks": "Google cn", "remarks": "Google cn",
"outboundTag": "proxy", "outboundTag": "proxy",
@@ -42,21 +49,89 @@
] ]
}, },
{ {
"remarks": "代理GFW", "remarks": "代理海外公共DNSIP",
"outboundTag": "proxy", "outboundTag": "proxy",
"domain": [ "ip": [
"geosite:gfw", "1.1.1.1",
"geosite:greatfire" "1.0.0.1",
"2606:4700:4700::1111",
"2606:4700:4700::1001",
"1.1.1.2",
"1.0.0.2",
"2606:4700:4700::1112",
"2606:4700:4700::1002",
"1.1.1.3",
"1.0.0.3",
"2606:4700:4700::1113",
"2606:4700:4700::1003",
"8.8.8.8",
"8.8.4.4",
"2001:4860:4860::8888",
"2001:4860:4860::8844",
"94.140.14.14",
"94.140.15.15",
"2a10:50c0::ad1:ff",
"2a10:50c0::ad2:ff",
"94.140.14.15",
"94.140.15.16",
"2a10:50c0::bad1:ff",
"2a10:50c0::bad2:ff",
"94.140.14.140",
"94.140.14.141",
"2a10:50c0::1:ff",
"2a10:50c0::2:ff",
"208.67.222.222",
"208.67.220.220",
"2620:119:35::35",
"2620:119:53::53",
"208.67.222.123",
"208.67.220.123",
"2620:119:35::123",
"2620:119:53::123",
"9.9.9.9",
"149.112.112.112",
"2620:fe::9",
"2620:fe::fe",
"9.9.9.11",
"149.112.112.11",
"2620:fe::11",
"2620:fe::fe:11",
"9.9.9.10",
"149.112.112.10",
"2620:fe::10",
"2620:fe::fe:10",
"77.88.8.8",
"77.88.8.1",
"2a02:6b8::feed:0ff",
"2a02:6b8:0:1::feed:0ff",
"77.88.8.88",
"77.88.8.2",
"2a02:6b8::feed:bad",
"2a02:6b8:0:1::feed:bad",
"77.88.8.7",
"77.88.8.3",
"2a02:6b8::feed:a11",
"2a02:6b8:0:1::feed:a11"
] ]
}, },
{ {
"remarks": "代理Google等", "remarks": "代理海外公共DNS域名",
"outboundTag": "proxy",
"domain": [
"domain:cloudflare-dns.com",
"domain:one.one.one.one",
"domain:dns.google",
"domain:adguard-dns.com",
"domain:opendns.com",
"domain:umbrella.com",
"domain:quad9.net",
"domain:yandex.net"
]
},
{
"remarks": "代理IP",
"outboundTag": "proxy", "outboundTag": "proxy",
"ip": [ "ip": [
"1.0.0.1",
"1.1.1.1",
"8.8.8.8",
"8.8.4.4",
"geoip:facebook", "geoip:facebook",
"geoip:fastly", "geoip:fastly",
"geoip:google", "geoip:google",
@@ -65,6 +140,14 @@
"geoip:twitter" "geoip:twitter"
] ]
}, },
{
"remarks": "代理GFW",
"outboundTag": "proxy",
"domain": [
"geosite:gfw",
"geosite:greatfire"
]
},
{ {
"remarks": "最终直连", "remarks": "最终直连",
"port": "0-65535", "port": "0-65535",

View File

@@ -1,21 +0,0 @@
[
{
"domain": [
"geosite:google"
],
"outboundTag": "proxy"
},
{
"outboundTag": "direct",
"domain": [
"domain:example-example.com",
"domain:example-example2.com"
]
},
{
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
}
]

View File

@@ -1,28 +0,0 @@
[{
"remarks": "block",
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
},
{
"remarks": "direct",
"outboundTag": "direct",
"domain": [
"geosite:cn"
]
},
{
"remarks": "direct",
"outboundTag": "direct",
"ip": [
"geoip:private",
"geoip:cn"
]
},
{
"remarks": "proxy",
"port": "0-65535",
"outboundTag": "proxy"
}
]

View File

@@ -35,47 +35,69 @@
] ]
}, },
{ {
"remarks": "绕过中国域名", "remarks": "绕过中国公共DNSIP",
"outboundTag": "direct",
"ip": [
"223.5.5.5",
"223.6.6.6",
"2400:3200::1",
"2400:3200:baba::1",
"119.29.29.29",
"1.12.12.12",
"120.53.53.53",
"2402:4e00::",
"2402:4e00:1::",
"180.76.76.76",
"2400:da00::6666",
"114.114.114.114",
"114.114.115.115",
"114.114.114.119",
"114.114.115.119",
"114.114.114.110",
"114.114.115.110",
"180.184.1.1",
"180.184.2.2",
"101.226.4.6",
"218.30.118.6",
"123.125.81.6",
"140.207.198.6",
"1.2.4.8",
"210.2.4.8",
"52.80.66.66",
"117.50.22.22",
"2400:7fc0:849e:200::4",
"2404:c2c0:85d8:901::4",
"117.50.10.10",
"52.80.52.52",
"2400:7fc0:849e:200::8",
"2404:c2c0:85d8:901::8",
"117.50.60.30",
"52.80.60.30"
]
},
{
"remarks": "绕过中国公共DNS域名",
"outboundTag": "direct", "outboundTag": "direct",
"domain": [ "domain": [
"domain:dns.alidns.com", "domain:alidns.com",
"domain:doh.pub", "domain:doh.pub",
"domain:dot.pub", "domain:dot.pub",
"domain:doh.360.cn", "domain:360.cn",
"domain:dot.360.cn", "domain:onedns.net"
"geosite:cn",
"geosite:geolocation-cn"
] ]
}, },
{ {
"remarks": "绕过中国IP", "remarks": "绕过中国IP",
"outboundTag": "direct", "outboundTag": "direct",
"ip": [ "ip": [
"223.5.5.5/32",
"223.6.6.6/32",
"2400:3200::1/128",
"2400:3200:baba::1/128",
"119.29.29.29/32",
"1.12.12.12/32",
"120.53.53.53/32",
"2402:4e00::/128",
"2402:4e00:1::/128",
"180.76.76.76/32",
"2400:da00::6666/128",
"114.114.114.114/32",
"114.114.115.115/32",
"180.184.1.1/32",
"180.184.2.2/32",
"101.226.4.6/32",
"218.30.118.6/32",
"123.125.81.6/32",
"140.207.198.6/32",
"geoip:cn" "geoip:cn"
] ]
}, },
{ {
"remarks": "最终代理", "remarks": "绕过中国域名",
"port": "0-65535", "outboundTag": "direct",
"outboundTag": "proxy" "domain": [
"geosite:cn"
]
} }
] ]

View File

@@ -20,8 +20,7 @@
"rules": [ "rules": [
{ {
"rule_set": [ "rule_set": [
"geosite-cn", "geosite-cn"
"geosite-geolocation-cn"
], ],
"server": "local" "server": "local"
}, },

View File

@@ -7,8 +7,7 @@
{ {
"address": "223.5.5.5", "address": "223.5.5.5",
"domains": [ "domains": [
"geosite:cn", "geosite:cn"
"geosite:geolocation-cn"
], ],
"expectIPs": [ "expectIPs": [
"geoip:cn" "geoip:cn"

View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Application
Exec=$ExecPath$
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_US]=v2rayN
Name=v2rayN
Comment[en_US]=v2rayN
Comment=v2rayN

View File

@@ -2,8 +2,10 @@
"type": "tun", "type": "tun",
"tag": "tun-in", "tag": "tun-in",
"interface_name": "singbox_tun", "interface_name": "singbox_tun",
"inet4_address": "172.19.0.1/30", "address": [
"inet6_address": "fdfe:dcba:9876::1/126", "172.18.0.1/30",
"fdfe:dcba:9876::1/126"
],
"mtu": 9000, "mtu": 9000,
"auto_route": true, "auto_route": true,
"strict_route": false, "strict_route": false,

View File

@@ -4,21 +4,23 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>7.0.3</Version> <Version>7.5.1</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Downloader" Version="3.2.1" /> <PackageReference Include="Downloader" Version="3.3.1" />
<PackageReference Include="ReactiveUI" Version="20.1.63" /> <PackageReference Include="ReactiveUI" Version="20.1.63" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" /> <PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" /> <PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="Splat.NLog" Version="15.2.22" /> <PackageReference Include="Splat.NLog" Version="15.2.22" />
<PackageReference Include="WebDav.Client" Version="2.8.0" /> <PackageReference Include="WebDav.Client" Version="2.8.0" />
<PackageReference Include="YamlDotNet" Version="16.1.3" /> <PackageReference Include="YamlDotNet" Version="16.3.0" />
<PackageReference Include="QRCoder" Version="1.6.0" /> <PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="CliWrap" Version="3.6.6" /> <PackageReference Include="CliWrap" Version="3.7.0" />
<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" /> <PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />
<PackageReference Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" /> <PackageReference Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
<PackageReference Include="TaskScheduler" Version="2.11.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -26,11 +28,10 @@
<EmbeddedResource Include="Sample\clash_tun_yaml" /> <EmbeddedResource Include="Sample\clash_tun_yaml" />
<EmbeddedResource Include="Sample\custom_routing_black" /> <EmbeddedResource Include="Sample\custom_routing_black" />
<EmbeddedResource Include="Sample\custom_routing_global" /> <EmbeddedResource Include="Sample\custom_routing_global" />
<EmbeddedResource Include="Sample\custom_routing_locked" />
<EmbeddedResource Include="Sample\custom_routing_rules" />
<EmbeddedResource Include="Sample\custom_routing_white" /> <EmbeddedResource Include="Sample\custom_routing_white" />
<EmbeddedResource Include="Sample\dns_singbox_normal" /> <EmbeddedResource Include="Sample\dns_singbox_normal" />
<EmbeddedResource Include="Sample\dns_v2ray_normal" /> <EmbeddedResource Include="Sample\dns_v2ray_normal" />
<EmbeddedResource Include="Sample\pac" />
<EmbeddedResource Include="Sample\SampleClientConfig" /> <EmbeddedResource Include="Sample\SampleClientConfig" />
<EmbeddedResource Include="Sample\SampleHttpRequest" /> <EmbeddedResource Include="Sample\SampleHttpRequest" />
<EmbeddedResource Include="Sample\SampleHttpResponse" /> <EmbeddedResource Include="Sample\SampleHttpResponse" />
@@ -41,14 +42,9 @@
<EmbeddedResource Include="Sample\tun_singbox_dns" /> <EmbeddedResource Include="Sample\tun_singbox_dns" />
<EmbeddedResource Include="Sample\tun_singbox_inbound" /> <EmbeddedResource Include="Sample\tun_singbox_inbound" />
<EmbeddedResource Include="Sample\tun_singbox_rules" /> <EmbeddedResource Include="Sample\tun_singbox_rules" />
<EmbeddedResource Include="Sample\linux_autostart_config" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PacLib\PacLib.csproj" />
<ProjectReference Include="..\ProtosLib\ProtosLib.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Resx\ResUI.Designer.cs"> <Compile Update="Resx\ResUI.Designer.cs">
<DependentUpon>ResUI.resx</DependentUpon> <DependentUpon>ResUI.resx</DependentUpon>
@@ -62,6 +58,9 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Update="Resx\ResUI.hu.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resx\ResUI.resx"> <EmbeddedResource Update="Resx\ResUI.resx">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<LastGenOutput>ResUI.Designer.cs</LastGenOutput> <LastGenOutput>ResUI.Designer.cs</LastGenOutput>

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Services.CoreConfig namespace ServiceLib.Services.CoreConfig
{ {
/// <summary> /// <summary>
/// Core configuration file processing class /// Core configuration file processing class
@@ -66,7 +66,7 @@
txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2); txtFile = txtFile.Replace(tagYamlStr1, tagYamlStr2);
//YAML anchors //YAML anchors
if (txtFile.Contains("<<:") && txtFile.Contains("*") && txtFile.Contains("&")) if (txtFile.Contains("<<:") && txtFile.Contains('*') && txtFile.Contains('&'))
{ {
txtFile = YamlUtils.PreprocessYaml(txtFile); txtFile = YamlUtils.PreprocessYaml(txtFile);
} }
@@ -78,17 +78,15 @@
return ret; return ret;
} }
//port //mixed-port
fileContent["port"] = AppHandler.Instance.GetLocalPort(EInboundProtocol.http); fileContent["mixed-port"] = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
//socks-port
fileContent["socks-port"] = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
//log-level //log-level
fileContent["log-level"] = GetLogLevel(_config.CoreBasicItem.Loglevel); fileContent["log-level"] = GetLogLevel(_config.CoreBasicItem.Loglevel);
//external-controller //external-controller
fileContent["external-controller"] = $"{Global.Loopback}:{AppHandler.Instance.StatePort2}"; fileContent["external-controller"] = $"{Global.Loopback}:{AppHandler.Instance.StatePort2}";
//allow-lan //allow-lan
if (_config.Inbound[0].AllowLANConn) if (_config.Inbound.First().AllowLANConn)
{ {
fileContent["allow-lan"] = "true"; fileContent["allow-lan"] = "true";
fileContent["bind-address"] = "*"; fileContent["bind-address"] = "*";

View File

@@ -1,4 +1,4 @@
using System.Data; using System.Data;
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
@@ -26,7 +26,7 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.CheckServerSettings; ret.Msg = ResUI.CheckServerSettings;
return ret; return ret;
} }
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.splithttp)) if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp))
{ {
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret; return ret;
@@ -52,7 +52,7 @@ namespace ServiceLib.Services.CoreConfig
await GenInbounds(singboxConfig); await GenInbounds(singboxConfig);
await GenOutbound(node, singboxConfig.outbounds[0]); await GenOutbound(node, singboxConfig.outbounds.First());
await GenMoreOutbounds(node, singboxConfig); await GenMoreOutbounds(node, singboxConfig);
@@ -90,8 +90,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient); var result = Utils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -119,10 +119,10 @@ namespace ServiceLib.Services.CoreConfig
await GenLog(singboxConfig); await GenLog(singboxConfig);
//GenDns(new(), singboxConfig); //GenDns(new(), singboxConfig);
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts. singboxConfig.inbounds.Clear();
singboxConfig.outbounds.RemoveAt(0); singboxConfig.outbounds.RemoveAt(0);
int httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest); var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
@@ -144,8 +144,8 @@ namespace ServiceLib.Services.CoreConfig
} }
//find unused port //find unused port
var port = httpPort; var port = initPort;
for (int k = httpPort; k < Global.MaxPort; k++) for (int k = initPort; k < Global.MaxPort; k++)
{ {
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{ {
@@ -157,7 +157,7 @@ namespace ServiceLib.Services.CoreConfig
} }
//found //found
port = k; port = k;
httpPort = port + 1; initPort = port + 1;
break; break;
} }
@@ -174,7 +174,7 @@ namespace ServiceLib.Services.CoreConfig
{ {
listen = Global.Loopback, listen = Global.Loopback,
listen_port = port, listen_port = port,
type = EInboundProtocol.http.ToString(), type = EInboundProtocol.mixed.ToString(),
}; };
inbound.tag = inbound.type + inbound.listen_port.ToString(); inbound.tag = inbound.type + inbound.listen_port.ToString();
singboxConfig.inbounds.Add(inbound); singboxConfig.inbounds.Add(inbound);
@@ -409,7 +409,9 @@ namespace ServiceLib.Services.CoreConfig
{ {
await GenInbounds(singboxConfig); await GenInbounds(singboxConfig);
await GenExperimental(singboxConfig); await GenExperimental(singboxConfig);
JsonUtils.ToFile(singboxConfig, fileName, false);
var content = JsonUtils.Serialize(singboxConfig, true);
await File.WriteAllTextAsync(fileName, content);
} }
} }
else else
@@ -440,7 +442,7 @@ namespace ServiceLib.Services.CoreConfig
#region private gen function #region private gen function
public async Task<int> GenLog(SingboxConfig singboxConfig) private async Task<int> GenLog(SingboxConfig singboxConfig)
{ {
try try
{ {
@@ -484,57 +486,50 @@ namespace ServiceLib.Services.CoreConfig
singboxConfig.inbounds = []; singboxConfig.inbounds = [];
if (!_config.TunModeItem.EnableTun if (!_config.TunModeItem.EnableTun
|| _config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && _config.RunningCoreType == ECoreType.sing_box) || (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && _config.RunningCoreType == ECoreType.sing_box))
{ {
var inbound = new Inbound4Sbox() var inbound = new Inbound4Sbox()
{ {
type = EInboundProtocol.socks.ToString(), type = EInboundProtocol.mixed.ToString(),
tag = EInboundProtocol.socks.ToString(), tag = EInboundProtocol.socks.ToString(),
listen = Global.Loopback, listen = Global.Loopback,
}; };
singboxConfig.inbounds.Add(inbound); singboxConfig.inbounds.Add(inbound);
inbound.listen_port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks); inbound.listen_port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
inbound.sniff = _config.Inbound[0].SniffingEnabled; inbound.sniff = _config.Inbound.First().SniffingEnabled;
inbound.sniff_override_destination = _config.Inbound[0].RouteOnly ? false : _config.Inbound[0].SniffingEnabled; inbound.sniff_override_destination = _config.Inbound.First().RouteOnly ? false : _config.Inbound.First().SniffingEnabled;
inbound.domain_strategy = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainStrategy4Singbox) ? null : _config.RoutingBasicItem.DomainStrategy4Singbox; inbound.domain_strategy = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainStrategy4Singbox) ? null : _config.RoutingBasicItem.DomainStrategy4Singbox;
if (_config.RoutingBasicItem.EnableRoutingAdvanced) var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.DomainStrategy4Singbox))
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); inbound.domain_strategy = routing.DomainStrategy4Singbox;
if (Utils.IsNotEmpty(routing.DomainStrategy4Singbox))
{
inbound.domain_strategy = routing.DomainStrategy4Singbox;
}
} }
//http if (_config.Inbound.First().SecondLocalPortEnabled)
var inbound2 = GetInbound(inbound, EInboundProtocol.http, false);
singboxConfig.inbounds.Add(inbound2);
if (_config.Inbound[0].AllowLANConn)
{ {
if (_config.Inbound[0].NewPort4LAN) var inbound2 = GetInbound(inbound, EInboundProtocol.socks2, true);
singboxConfig.inbounds.Add(inbound2);
}
if (_config.Inbound.First().AllowLANConn)
{
if (_config.Inbound.First().NewPort4LAN)
{ {
var inbound3 = GetInbound(inbound, EInboundProtocol.socks2, true); var inbound3 = GetInbound(inbound, EInboundProtocol.socks3, true);
inbound3.listen = listen; inbound3.listen = listen;
singboxConfig.inbounds.Add(inbound3); singboxConfig.inbounds.Add(inbound3);
var inbound4 = GetInbound(inbound, EInboundProtocol.http2, false);
inbound4.listen = listen;
singboxConfig.inbounds.Add(inbound4);
//auth //auth
if (Utils.IsNotEmpty(_config.Inbound[0].User) && Utils.IsNotEmpty(_config.Inbound[0].Pass)) if (Utils.IsNotEmpty(_config.Inbound.First().User) && Utils.IsNotEmpty(_config.Inbound.First().Pass))
{ {
inbound3.users = new() { new() { username = _config.Inbound[0].User, password = _config.Inbound[0].Pass } }; inbound3.users = new() { new() { username = _config.Inbound.First().User, password = _config.Inbound.First().Pass } };
inbound4.users = new() { new() { username = _config.Inbound[0].User, password = _config.Inbound[0].Pass } };
} }
} }
else else
{ {
inbound.listen = listen; inbound.listen = listen;
inbound2.listen = listen;
} }
} }
} }
@@ -543,22 +538,23 @@ namespace ServiceLib.Services.CoreConfig
{ {
if (_config.TunModeItem.Mtu <= 0) if (_config.TunModeItem.Mtu <= 0)
{ {
_config.TunModeItem.Mtu = Utils.ToInt(Global.TunMtus[0]); _config.TunModeItem.Mtu = Utils.ToInt(Global.TunMtus.First());
} }
if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack)) if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack))
{ {
_config.TunModeItem.Stack = Global.TunStacks[0]; _config.TunModeItem.Stack = Global.TunStacks.First();
} }
var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(Utils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { }; var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(Utils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { };
tunInbound.interface_name = Utils.IsOSX() ? $"utun{new Random().Next(99)}" : "singbox_tun";
tunInbound.mtu = _config.TunModeItem.Mtu; tunInbound.mtu = _config.TunModeItem.Mtu;
tunInbound.strict_route = _config.TunModeItem.StrictRoute; tunInbound.strict_route = _config.TunModeItem.StrictRoute;
tunInbound.stack = _config.TunModeItem.Stack; tunInbound.stack = _config.TunModeItem.Stack;
tunInbound.sniff = _config.Inbound[0].SniffingEnabled; tunInbound.sniff = _config.Inbound.First().SniffingEnabled;
//tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled; //tunInbound.sniff_override_destination = _config.inbound.First().routeOnly ? false : _config.inbound.First().sniffingEnabled;
if (_config.TunModeItem.EnableIPv6Address == false) if (_config.TunModeItem.EnableIPv6Address == false)
{ {
tunInbound.inet6_address = null; tunInbound.address = ["172.18.0.1/30"];
} }
singboxConfig.inbounds.Add(tunInbound); singboxConfig.inbounds.Add(tunInbound);
@@ -576,11 +572,11 @@ namespace ServiceLib.Services.CoreConfig
var inbound = JsonUtils.DeepCopy(inItem); var inbound = JsonUtils.DeepCopy(inItem);
inbound.tag = protocol.ToString(); inbound.tag = protocol.ToString();
inbound.listen_port = inItem.listen_port + (int)protocol; inbound.listen_port = inItem.listen_port + (int)protocol;
inbound.type = bSocks ? EInboundProtocol.socks.ToString() : EInboundProtocol.http.ToString(); inbound.type = EInboundProtocol.mixed.ToString();
return inbound; return inbound;
} }
public async Task<int> GenOutbound(ProfileItem node, Outbound4Sbox outbound) private async Task<int> GenOutbound(ProfileItem node, Outbound4Sbox outbound)
{ {
try try
{ {
@@ -704,7 +700,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenOutboundMux(ProfileItem node, Outbound4Sbox outbound) private async Task<int> GenOutboundMux(ProfileItem node, Outbound4Sbox outbound)
{ {
try try
{ {
@@ -727,7 +723,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenOutboundTls(ProfileItem node, Outbound4Sbox outbound) private async Task<int> GenOutboundTls(ProfileItem node, Outbound4Sbox outbound)
{ {
try try
{ {
@@ -777,7 +773,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenOutboundTransport(ProfileItem node, Outbound4Sbox outbound) private async Task<int> GenOutboundTransport(ProfileItem node, Outbound4Sbox outbound)
{ {
try try
{ {
@@ -869,7 +865,7 @@ namespace ServiceLib.Services.CoreConfig
} }
//current proxy //current proxy
var outbound = singboxConfig.outbounds[0]; var outbound = singboxConfig.outbounds.First();
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
//Previous proxy //Previous proxy
@@ -912,7 +908,7 @@ namespace ServiceLib.Services.CoreConfig
try try
{ {
var dnsOutbound = "dns_out"; var dnsOutbound = "dns_out";
if (!_config.Inbound[0].SniffingEnabled) if (!_config.Inbound.First().SniffingEnabled)
{ {
singboxConfig.route.rules.Add(new() singboxConfig.route.rules.Add(new()
{ {
@@ -958,28 +954,13 @@ namespace ServiceLib.Services.CoreConfig
}); });
} }
if (_config.RoutingBasicItem.EnableRoutingAdvanced) var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
if (routing != null) foreach (var item in rules ?? [])
{ {
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet); if (item.Enabled)
foreach (var item in rules ?? [])
{
if (item.Enabled)
{
await GenRoutingUserRule(item, singboxConfig.route.rules);
}
}
}
}
else
{
var lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (lockedItem != null)
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(lockedItem.RuleSet);
foreach (var item in rules ?? [])
{ {
await GenRoutingUserRule(item, singboxConfig.route.rules); await GenRoutingUserRule(item, singboxConfig.route.rules);
} }
@@ -1019,7 +1000,7 @@ namespace ServiceLib.Services.CoreConfig
} }
} }
public async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules) private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
{ {
try try
{ {
@@ -1177,7 +1158,7 @@ namespace ServiceLib.Services.CoreConfig
return true; return true;
} }
public async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig) private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
{ {
try try
{ {
@@ -1208,7 +1189,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem) private async Task<int> GenDnsDomains(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
{ {
var dns4Sbox = singboxConfig.dns ?? new(); var dns4Sbox = singboxConfig.dns ?? new();
dns4Sbox.servers ??= []; dns4Sbox.servers ??= [];
@@ -1261,7 +1242,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenExperimental(SingboxConfig singboxConfig) private async Task<int> GenExperimental(SingboxConfig singboxConfig)
{ {
//if (_config.guiItem.enableStatistics) //if (_config.guiItem.enableStatistics)
{ {
@@ -1334,20 +1315,18 @@ namespace ServiceLib.Services.CoreConfig
//load custom ruleset file //load custom ruleset file
List<Ruleset4Sbox> customRulesets = []; List<Ruleset4Sbox> customRulesets = [];
if (_config.RoutingBasicItem.EnableRoutingAdvanced)
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox))
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox)) if (Utils.IsNotEmpty(result))
{ {
var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox); customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
if (Utils.IsNotEmpty(result)) .Where(t => t.tag != null)
{ .Where(t => t.type != null)
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? []) .Where(t => t.format != null)
.Where(t => t.tag != null) .ToList();
.Where(t => t.type != null)
.Where(t => t.format != null)
.ToList();
}
} }
} }

View File

@@ -27,6 +27,12 @@ namespace ServiceLib.Services.CoreConfig
return ret; return ret;
} }
if (node.GetNetwork() is nameof(ETransport.quic))
{
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret;
}
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
var result = Utils.GetEmbedText(Global.V2raySampleClient); var result = Utils.GetEmbedText(Global.V2raySampleClient);
@@ -49,7 +55,7 @@ namespace ServiceLib.Services.CoreConfig
await GenRouting(v2rayConfig); await GenRouting(v2rayConfig);
await GenOutbound(node, v2rayConfig.outbounds[0]); await GenOutbound(node, v2rayConfig.outbounds.First());
await GenMoreOutbounds(node, v2rayConfig); await GenMoreOutbounds(node, v2rayConfig);
@@ -210,8 +216,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient); var result = Utils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -238,10 +244,11 @@ namespace ServiceLib.Services.CoreConfig
} }
await GenLog(v2rayConfig); await GenLog(v2rayConfig);
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts. v2rayConfig.inbounds.Clear();
v2rayConfig.outbounds.RemoveAt(0); v2rayConfig.outbounds.Clear();
v2rayConfig.routing.rules.Clear();
int httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest); var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
@@ -263,8 +270,8 @@ namespace ServiceLib.Services.CoreConfig
} }
//find unused port //find unused port
var port = httpPort; var port = initPort;
for (int k = httpPort; k < Global.MaxPort; k++) for (var k = initPort; k < Global.MaxPort; k++)
{ {
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{ {
@@ -276,7 +283,7 @@ namespace ServiceLib.Services.CoreConfig
} }
//found //found
port = k; port = k;
httpPort = port + 1; initPort = port + 1;
break; break;
} }
@@ -288,16 +295,6 @@ namespace ServiceLib.Services.CoreConfig
it.Port = port; it.Port = port;
it.AllowTest = true; it.AllowTest = true;
//inbound
Inbounds4Ray inbound = new()
{
listen = Global.Loopback,
port = port,
protocol = EInboundProtocol.http.ToString(),
};
inbound.tag = inbound.protocol + inbound.port.ToString();
v2rayConfig.inbounds.Add(inbound);
//outbound //outbound
if (item is null) if (item is null)
{ {
@@ -320,6 +317,16 @@ namespace ServiceLib.Services.CoreConfig
continue; continue;
} }
//inbound
Inbounds4Ray inbound = new()
{
listen = Global.Loopback,
port = port,
protocol = EInboundProtocol.socks.ToString(),
};
inbound.tag = inbound.protocol + inbound.port.ToString();
v2rayConfig.inbounds.Add(inbound);
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound); var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(item, outbound); await GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.port.ToString(); outbound.tag = Global.ProxyTag + inbound.port.ToString();
@@ -352,7 +359,7 @@ namespace ServiceLib.Services.CoreConfig
#region private gen function #region private gen function
public async Task<int> GenLog(V2rayConfig v2rayConfig) private async Task<int> GenLog(V2rayConfig v2rayConfig)
{ {
try try
{ {
@@ -366,8 +373,8 @@ namespace ServiceLib.Services.CoreConfig
else else
{ {
v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel; v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = null;
v2rayConfig.log.error = ""; v2rayConfig.log.error = null;
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -377,46 +384,40 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenInbounds(V2rayConfig v2rayConfig) private async Task<int> GenInbounds(V2rayConfig v2rayConfig)
{ {
try try
{ {
var listen = "0.0.0.0"; var listen = "0.0.0.0";
v2rayConfig.inbounds = []; v2rayConfig.inbounds = [];
Inbounds4Ray? inbound = GetInbound(_config.Inbound[0], EInboundProtocol.socks, true); var inbound = GetInbound(_config.Inbound.First(), EInboundProtocol.socks, true);
v2rayConfig.inbounds.Add(inbound); v2rayConfig.inbounds.Add(inbound);
//http if (_config.Inbound.First().SecondLocalPortEnabled)
Inbounds4Ray? inbound2 = GetInbound(_config.Inbound[0], EInboundProtocol.http, false);
v2rayConfig.inbounds.Add(inbound2);
if (_config.Inbound[0].AllowLANConn)
{ {
if (_config.Inbound[0].NewPort4LAN) var inbound2 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks2, true);
v2rayConfig.inbounds.Add(inbound2);
}
if (_config.Inbound.First().AllowLANConn)
{
if (_config.Inbound.First().NewPort4LAN)
{ {
var inbound3 = GetInbound(_config.Inbound[0], EInboundProtocol.socks2, true); var inbound3 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks3, true);
inbound3.listen = listen; inbound3.listen = listen;
v2rayConfig.inbounds.Add(inbound3); v2rayConfig.inbounds.Add(inbound3);
var inbound4 = GetInbound(_config.Inbound[0], EInboundProtocol.http2, false);
inbound4.listen = listen;
v2rayConfig.inbounds.Add(inbound4);
//auth //auth
if (Utils.IsNotEmpty(_config.Inbound[0].User) && Utils.IsNotEmpty(_config.Inbound[0].Pass)) if (Utils.IsNotEmpty(_config.Inbound.First().User) && Utils.IsNotEmpty(_config.Inbound.First().Pass))
{ {
inbound3.settings.auth = "password"; inbound3.settings.auth = "password";
inbound3.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound[0].User, pass = _config.Inbound[0].Pass } }; inbound3.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound.First().User, pass = _config.Inbound.First().Pass } };
inbound4.settings.auth = "password";
inbound4.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound[0].User, pass = _config.Inbound[0].Pass } };
} }
} }
else else
{ {
inbound.listen = listen; inbound.listen = listen;
inbound2.listen = listen;
} }
} }
} }
@@ -442,7 +443,7 @@ namespace ServiceLib.Services.CoreConfig
} }
inbound.tag = protocol.ToString(); inbound.tag = protocol.ToString();
inbound.port = inItem.LocalPort + (int)protocol; inbound.port = inItem.LocalPort + (int)protocol;
inbound.protocol = bSocks ? EInboundProtocol.socks.ToString() : EInboundProtocol.http.ToString(); inbound.protocol = EInboundProtocol.socks.ToString();
inbound.settings.udp = inItem.UdpEnabled; inbound.settings.udp = inItem.UdpEnabled;
inbound.sniffing.enabled = inItem.SniffingEnabled; inbound.sniffing.enabled = inItem.SniffingEnabled;
inbound.sniffing.destOverride = inItem.DestOverride; inbound.sniffing.destOverride = inItem.DestOverride;
@@ -460,33 +461,17 @@ namespace ServiceLib.Services.CoreConfig
v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy; v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy;
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainMatcher) ? null : _config.RoutingBasicItem.DomainMatcher; v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainMatcher) ? null : _config.RoutingBasicItem.DomainMatcher;
if (_config.RoutingBasicItem.EnableRoutingAdvanced) var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); if (Utils.IsNotEmpty(routing.DomainStrategy))
if (routing != null)
{ {
if (Utils.IsNotEmpty(routing.DomainStrategy)) v2rayConfig.routing.domainStrategy = routing.DomainStrategy;
{
v2rayConfig.routing.domainStrategy = routing.DomainStrategy;
}
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules)
{
if (item.Enabled)
{
var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
await GenRoutingUserRule(item2, v2rayConfig);
}
}
} }
} var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
else foreach (var item in rules)
{
var lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (lockedItem != null)
{ {
var rules = JsonUtils.Deserialize<List<RulesItem>>(lockedItem.RuleSet); if (item.Enabled)
foreach (var item in rules)
{ {
var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item)); var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
await GenRoutingUserRule(item2, v2rayConfig); await GenRoutingUserRule(item2, v2rayConfig);
@@ -502,7 +487,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenRoutingUserRule(RulesItem4Ray? rule, V2rayConfig v2rayConfig) private async Task<int> GenRoutingUserRule(RulesItem4Ray? rule, V2rayConfig v2rayConfig)
{ {
try try
{ {
@@ -580,7 +565,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound) private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
{ {
try try
{ {
@@ -596,7 +581,7 @@ namespace ServiceLib.Services.CoreConfig
} }
else else
{ {
vnextItem = outbound.settings.vnext[0]; vnextItem = outbound.settings.vnext.First();
} }
vnextItem.address = node.Address; vnextItem.address = node.Address;
vnextItem.port = node.Port; vnextItem.port = node.Port;
@@ -609,7 +594,7 @@ namespace ServiceLib.Services.CoreConfig
} }
else else
{ {
usersItem = vnextItem.users[0]; usersItem = vnextItem.users.First();
} }
//远程服务器用户ID //远程服务器用户ID
usersItem.id = node.Id; usersItem.id = node.Id;
@@ -639,7 +624,7 @@ namespace ServiceLib.Services.CoreConfig
} }
else else
{ {
serversItem = outbound.settings.servers[0]; serversItem = outbound.settings.servers.First();
} }
serversItem.address = node.Address; serversItem.address = node.Address;
serversItem.port = node.Port; serversItem.port = node.Port;
@@ -665,7 +650,7 @@ namespace ServiceLib.Services.CoreConfig
} }
else else
{ {
serversItem = outbound.settings.servers[0]; serversItem = outbound.settings.servers.First();
} }
serversItem.address = node.Address; serversItem.address = node.Address;
serversItem.port = node.Port; serversItem.port = node.Port;
@@ -700,7 +685,7 @@ namespace ServiceLib.Services.CoreConfig
} }
else else
{ {
vnextItem = outbound.settings.vnext[0]; vnextItem = outbound.settings.vnext.First();
} }
vnextItem.address = node.Address; vnextItem.address = node.Address;
vnextItem.port = node.Port; vnextItem.port = node.Port;
@@ -713,7 +698,7 @@ namespace ServiceLib.Services.CoreConfig
} }
else else
{ {
usersItem = vnextItem.users[0]; usersItem = vnextItem.users.First();
} }
usersItem.id = node.Id; usersItem.id = node.Id;
usersItem.email = Global.UserEMail; usersItem.email = Global.UserEMail;
@@ -721,8 +706,7 @@ namespace ServiceLib.Services.CoreConfig
await GenOutboundMux(node, outbound, _config.CoreBasicItem.MuxEnabled); await GenOutboundMux(node, outbound, _config.CoreBasicItem.MuxEnabled);
if (node.StreamSecurity == Global.StreamSecurityReality if (node.StreamSecurity == Global.StreamSecurityReality || node.StreamSecurity == Global.StreamSecurity)
|| node.StreamSecurity == Global.StreamSecurity)
{ {
if (Utils.IsNotEmpty(node.Flow)) if (Utils.IsNotEmpty(node.Flow))
{ {
@@ -749,7 +733,7 @@ namespace ServiceLib.Services.CoreConfig
} }
else else
{ {
serversItem = outbound.settings.servers[0]; serversItem = outbound.settings.servers.First();
} }
serversItem.address = node.Address; serversItem.address = node.Address;
serversItem.port = node.Port; serversItem.port = node.Port;
@@ -766,7 +750,7 @@ namespace ServiceLib.Services.CoreConfig
} }
outbound.protocol = Global.ProtocolTypes[node.ConfigType]; outbound.protocol = Global.ProtocolTypes[node.ConfigType];
await GenBoundStreamSettings(node, outbound.streamSettings); await GenBoundStreamSettings(node, outbound);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -775,7 +759,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabled) private async Task<int> GenOutboundMux(ProfileItem node, Outbounds4Ray outbound, bool enabled)
{ {
try try
{ {
@@ -799,14 +783,16 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenBoundStreamSettings(ProfileItem node, StreamSettings4Ray streamSettings) private async Task<int> GenBoundStreamSettings(ProfileItem node, Outbounds4Ray outbound)
{ {
try try
{ {
var streamSettings = outbound.streamSettings;
streamSettings.network = node.GetNetwork(); streamSettings.network = node.GetNetwork();
string host = node.RequestHost.TrimEx(); var host = node.RequestHost.TrimEx();
string sni = node.Sni; var path = node.Path.TrimEx();
string useragent = ""; var sni = node.Sni.TrimEx();
var useragent = "";
if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty()) if (!_config.CoreBasicItem.DefUserAgent.IsNullOrEmpty())
{ {
try try
@@ -879,9 +865,9 @@ namespace ServiceLib.Services.CoreConfig
{ {
type = node.HeaderType type = node.HeaderType
}; };
if (Utils.IsNotEmpty(node.Path)) if (Utils.IsNotEmpty(path))
{ {
kcpSettings.seed = node.Path; kcpSettings.seed = path;
} }
streamSettings.kcpSettings = kcpSettings; streamSettings.kcpSettings = kcpSettings;
break; break;
@@ -889,9 +875,10 @@ namespace ServiceLib.Services.CoreConfig
case nameof(ETransport.ws): case nameof(ETransport.ws):
WsSettings4Ray wsSettings = new(); WsSettings4Ray wsSettings = new();
wsSettings.headers = new Headers4Ray(); wsSettings.headers = new Headers4Ray();
string path = node.Path;
if (Utils.IsNotEmpty(host)) if (Utils.IsNotEmpty(host))
{ {
wsSettings.host = host;
wsSettings.headers.Host = host; wsSettings.headers.Host = host;
} }
if (Utils.IsNotEmpty(path)) if (Utils.IsNotEmpty(path))
@@ -909,9 +896,9 @@ namespace ServiceLib.Services.CoreConfig
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
HttpupgradeSettings4Ray httpupgradeSettings = new(); HttpupgradeSettings4Ray httpupgradeSettings = new();
if (Utils.IsNotEmpty(node.Path)) if (Utils.IsNotEmpty(path))
{ {
httpupgradeSettings.path = node.Path; httpupgradeSettings.path = path;
} }
if (Utils.IsNotEmpty(host)) if (Utils.IsNotEmpty(host))
{ {
@@ -920,23 +907,30 @@ namespace ServiceLib.Services.CoreConfig
streamSettings.httpupgradeSettings = httpupgradeSettings; streamSettings.httpupgradeSettings = httpupgradeSettings;
break; break;
//splithttp //xhttp
case nameof(ETransport.splithttp): case nameof(ETransport.xhttp):
SplithttpSettings4Ray splithttpSettings = new() streamSettings.network = ETransport.xhttp.ToString();
{ XhttpSettings4Ray xhttpSettings = new();
maxUploadSize = 1000000,
maxConcurrentUploads = 10
};
if (Utils.IsNotEmpty(node.Path)) if (Utils.IsNotEmpty(path))
{ {
splithttpSettings.path = node.Path; xhttpSettings.path = path;
} }
if (Utils.IsNotEmpty(host)) if (Utils.IsNotEmpty(host))
{ {
splithttpSettings.host = host; xhttpSettings.host = host;
} }
streamSettings.splithttpSettings = splithttpSettings; if (Utils.IsNotEmpty(node.HeaderType) && Global.XhttpMode.Contains(node.HeaderType))
{
xhttpSettings.mode = node.HeaderType;
}
if (Utils.IsNotEmpty(node.Extra))
{
xhttpSettings.extra = JsonUtils.ParseJson(node.Extra);
}
streamSettings.xhttpSettings = xhttpSettings;
await GenOutboundMux(node, outbound, false);
break; break;
//h2 //h2
@@ -947,7 +941,7 @@ namespace ServiceLib.Services.CoreConfig
{ {
httpSettings.host = Utils.String2List(host); httpSettings.host = Utils.String2List(host);
} }
httpSettings.path = node.Path; httpSettings.path = path;
streamSettings.httpSettings = httpSettings; streamSettings.httpSettings = httpSettings;
@@ -957,7 +951,7 @@ namespace ServiceLib.Services.CoreConfig
QuicSettings4Ray quicsettings = new() QuicSettings4Ray quicsettings = new()
{ {
security = host, security = host,
key = node.Path, key = path,
header = new Header4Ray header = new Header4Ray
{ {
type = node.HeaderType type = node.HeaderType
@@ -981,7 +975,7 @@ namespace ServiceLib.Services.CoreConfig
GrpcSettings4Ray grpcSettings = new() GrpcSettings4Ray grpcSettings = new()
{ {
authority = Utils.IsNullOrEmpty(host) ? null : host, authority = Utils.IsNullOrEmpty(host) ? null : host,
serviceName = node.Path, serviceName = path,
multiMode = node.HeaderType == Global.GrpcMultiMode, multiMode = node.HeaderType == Global.GrpcMultiMode,
idle_timeout = _config.GrpcItem.IdleTimeout, idle_timeout = _config.GrpcItem.IdleTimeout,
health_check_timeout = _config.GrpcItem.HealthCheckTimeout, health_check_timeout = _config.GrpcItem.HealthCheckTimeout,
@@ -1006,18 +1000,17 @@ namespace ServiceLib.Services.CoreConfig
//request Host //request Host
string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName); string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
string[] arrHost = host.Split(','); string[] arrHost = host.Split(',');
string host2 = string.Join("\",\"", arrHost); string host2 = string.Join(",".AppendQuotes(), arrHost);
request = request.Replace("$requestHost$", $"\"{host2}\""); request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost())); request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
//Path //Path
string pathHttp = @"/"; string pathHttp = @"/";
if (Utils.IsNotEmpty(node.Path)) if (Utils.IsNotEmpty(path))
{ {
string[] arrPath = node.Path.Split(','); string[] arrPath = path.Split(',');
pathHttp = string.Join("\",\"", arrPath); pathHttp = string.Join(",".AppendQuotes(), arrPath);
} }
request = request.Replace("$requestPath$", $"\"{pathHttp}\""); request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
tcpSettings.header.request = JsonUtils.Deserialize<object>(request); tcpSettings.header.request = JsonUtils.Deserialize<object>(request);
streamSettings.tcpSettings = tcpSettings; streamSettings.tcpSettings = tcpSettings;
@@ -1032,7 +1025,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig) private async Task<int> GenDns(ProfileItem? node, V2rayConfig v2rayConfig)
{ {
try try
{ {
@@ -1095,7 +1088,7 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem) private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
{ {
if (node == null) if (node == null)
{ return 0; } { return 0; }
@@ -1115,22 +1108,19 @@ namespace ServiceLib.Services.CoreConfig
return 0; return 0;
} }
public async Task<int> GenStatistic(V2rayConfig v2rayConfig) private async Task<int> GenStatistic(V2rayConfig v2rayConfig)
{ {
if (_config.GuiItem.EnableStatistics) if (_config.GuiItem.EnableStatistics)
{ {
string tag = EInboundProtocol.api.ToString(); string tag = EInboundProtocol.api.ToString();
API4Ray apiObj = new(); Metrics4Ray apiObj = new();
Policy4Ray policyObj = new(); Policy4Ray policyObj = new();
SystemPolicy4Ray policySystemSetting = new(); SystemPolicy4Ray policySystemSetting = new();
string[] services = { "StatsService" };
v2rayConfig.stats = new Stats4Ray(); v2rayConfig.stats = new Stats4Ray();
apiObj.tag = tag; apiObj.tag = tag;
apiObj.services = services.ToList(); v2rayConfig.metrics = apiObj;
v2rayConfig.api = apiObj;
policySystemSetting.statsOutboundDownlink = true; policySystemSetting.statsOutboundDownlink = true;
policySystemSetting.statsOutboundUplink = true; policySystemSetting.statsOutboundUplink = true;
@@ -1169,7 +1159,7 @@ namespace ServiceLib.Services.CoreConfig
{ {
//fragment proxy //fragment proxy
if (_config.CoreBasicItem.EnableFragment if (_config.CoreBasicItem.EnableFragment
&& Utils.IsNotEmpty(v2rayConfig.outbounds[0].streamSettings?.security)) && Utils.IsNotEmpty(v2rayConfig.outbounds.First().streamSettings?.security))
{ {
var fragmentOutbound = new Outbounds4Ray var fragmentOutbound = new Outbounds4Ray
{ {
@@ -1187,7 +1177,7 @@ namespace ServiceLib.Services.CoreConfig
}; };
v2rayConfig.outbounds.Add(fragmentOutbound); v2rayConfig.outbounds.Add(fragmentOutbound);
v2rayConfig.outbounds[0].streamSettings.sockopt = new() v2rayConfig.outbounds.First().streamSettings.sockopt = new()
{ {
dialerProxy = fragmentOutbound.tag dialerProxy = fragmentOutbound.tag
}; };
@@ -1207,7 +1197,7 @@ namespace ServiceLib.Services.CoreConfig
} }
//current proxy //current proxy
var outbound = v2rayConfig.outbounds[0]; var outbound = v2rayConfig.outbounds.First();
var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
//Previous proxy //Previous proxy

View File

@@ -280,13 +280,13 @@ namespace ServiceLib.Services
{ {
return null; return null;
} }
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.http); var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
if (await SocketCheck(Global.Loopback, httpPort) == false) if (await SocketCheck(Global.Loopback, port) == false)
{ {
return null; return null;
} }
return new WebProxy(Global.Loopback, httpPort); return new WebProxy($"socks5://{Global.Loopback}:{port}");
} }
private async Task<bool> SocketCheck(string ip, int port) private async Task<bool> SocketCheck(string ip, int port)

View File

@@ -1,4 +1,5 @@
using System.Diagnostics; using ReactiveUI;
using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
@@ -7,19 +8,16 @@ namespace ServiceLib.Services
public class SpeedtestService public class SpeedtestService
{ {
private Config? _config; private Config? _config;
private List<ServerTestItem> _selecteds;
private ESpeedActionType _actionType;
private Action<SpeedTestResult>? _updateFunc; private Action<SpeedTestResult>? _updateFunc;
private bool _exitLoop = false; private bool _exitLoop = false;
public SpeedtestService(Config config, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> updateFunc) public SpeedtestService(Config config, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> updateFunc)
{ {
_config = config; _config = config;
_actionType = actionType;
_updateFunc = updateFunc; _updateFunc = updateFunc;
_selecteds = new List<ServerTestItem>(); var lstSelected = new List<ServerTestItem>();
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
if (it.ConfigType == EConfigType.Custom) if (it.ConfigType == EConfigType.Custom)
@@ -30,7 +28,7 @@ namespace ServiceLib.Services
{ {
continue; continue;
} }
_selecteds.Add(new ServerTestItem() lstSelected.Add(new ServerTestItem()
{ {
IndexId = it.IndexId, IndexId = it.IndexId,
Address = it.Address, Address = it.Address,
@@ -38,8 +36,9 @@ namespace ServiceLib.Services
ConfigType = it.ConfigType ConfigType = it.ConfigType
}); });
} }
//clear test result //clear test result
foreach (var it in _selecteds) foreach (var it in lstSelected)
{ {
switch (actionType) switch (actionType)
{ {
@@ -62,38 +61,74 @@ namespace ServiceLib.Services
} }
} }
switch (actionType) MessageBus.Current.Listen<string>(EMsgCommand.StopSpeedtest.ToString()).Subscribe(ExitLoop);
{
case ESpeedActionType.Tcping:
Task.Run(RunTcping);
break;
case ESpeedActionType.Realping: Task.Run(async () => { await RunAsync(actionType, lstSelected); });
Task.Run(RunRealPing);
break;
case ESpeedActionType.Speedtest:
Task.Run(RunSpeedTestAsync);
break;
case ESpeedActionType.Mixedtest:
Task.Run(RunMixedtestAsync);
break;
}
} }
public void ExitLoop() private async Task RunAsync(ESpeedActionType actionType, List<ServerTestItem> lstSelected)
{ {
if (actionType == ESpeedActionType.Tcping)
{
await RunTcpingAsync(lstSelected);
return;
}
var pageSize = _config.SpeedTestItem.SpeedTestPageSize;
if (pageSize is <= 0 or > 1000)
{
pageSize = 1000;
}
List<List<ServerTestItem>> lstTest = new();
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList();
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList();
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
{
lstTest.Add(lst1.Skip(num * pageSize).Take(pageSize).ToList());
}
for (var num = 0; num < (int)Math.Ceiling(lst2.Count * 1.0 / pageSize); num++)
{
lstTest.Add(lst2.Skip(num * pageSize).Take(pageSize).ToList());
}
foreach (var lst in lstTest)
{
switch (actionType)
{
case ESpeedActionType.Realping:
await RunRealPingAsync(lst);
break;
case ESpeedActionType.Speedtest:
await RunSpeedTestAsync(lst);
break;
case ESpeedActionType.Mixedtest:
await RunMixedTestAsync(lst);
break;
}
await Task.Delay(100);
}
UpdateFunc("", ResUI.SpeedtestingCompleted);
}
private void ExitLoop(string x)
{
if (_exitLoop) return;
_exitLoop = true; _exitLoop = true;
UpdateFunc("", ResUI.SpeedtestingStop); UpdateFunc("", ResUI.SpeedtestingStop);
} }
private async Task RunTcping() private async Task RunTcpingAsync(List<ServerTestItem> selecteds)
{ {
try try
{ {
List<Task> tasks = []; List<Task> tasks = [];
foreach (var it in _selecteds) foreach (var it in selecteds)
{ {
if (it.ConfigType == EConfigType.Custom) if (it.ConfigType == EConfigType.Custom)
{ {
@@ -103,7 +138,7 @@ namespace ServiceLib.Services
{ {
try try
{ {
int time = await GetTcpingTime(it.Address, it.Port); var time = await GetTcpingTime(it.Address, it.Port);
var output = FormatOut(time, Global.DelayUnit); var output = FormatOut(time, Global.DelayUnit);
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output); ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
@@ -127,24 +162,22 @@ namespace ServiceLib.Services
} }
} }
private async Task RunRealPing() private async Task RunRealPingAsync(List<ServerTestItem> selecteds)
{ {
int pid = -1; var pid = -1;
try try
{ {
string msg = string.Empty; pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
if (pid < 0) if (pid < 0)
{ {
UpdateFunc("", ResUI.FailedToRunCore); UpdateFunc("", ResUI.FailedToRunCore);
return; return;
} }
DownloadService downloadHandle = new DownloadService(); var downloadHandle = new DownloadService();
List<Task> tasks = new(); List<Task> tasks = new();
foreach (var it in _selecteds) foreach (var it in selecteds)
{ {
if (!it.AllowTest) if (!it.AllowTest)
{ {
@@ -158,12 +191,12 @@ namespace ServiceLib.Services
{ {
try try
{ {
WebProxy webProxy = new(Global.Loopback, it.Port); var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
string output = await GetRealPingTime(downloadHandle, webProxy); var output = await GetRealPingTime(downloadHandle, webProxy);
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output); ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
UpdateFunc(it.IndexId, output); UpdateFunc(it.IndexId, output);
int.TryParse(output, out int delay); int.TryParse(output, out var delay);
it.Delay = delay; it.Delay = delay;
} }
catch (Exception ex) catch (Exception ex)
@@ -182,33 +215,28 @@ namespace ServiceLib.Services
{ {
if (pid > 0) if (pid > 0)
{ {
CoreHandler.Instance.CoreStopPid(pid); await CoreHandler.Instance.CoreStopPid(pid);
} }
await ProfileExHandler.Instance.SaveTo(); await ProfileExHandler.Instance.SaveTo();
} }
} }
private async Task RunSpeedTestAsync() private async Task RunSpeedTestAsync(List<ServerTestItem> selecteds)
{ {
int pid = -1; var pid = -1;
//if (_actionType == ESpeedActionType.Mixedtest) pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
//{
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
//}
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
if (pid < 0) if (pid < 0)
{ {
UpdateFunc("", ResUI.FailedToRunCore); UpdateFunc("", ResUI.FailedToRunCore);
return; return;
} }
string url = _config.SpeedTestItem.SpeedTestUrl; var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout; var timeout = _config.SpeedTestItem.SpeedTestTimeout;
DownloadService downloadHandle = new(); DownloadService downloadHandle = new();
foreach (var it in _selecteds) foreach (var it in selecteds)
{ {
if (_exitLoop) if (_exitLoop)
{ {
@@ -234,11 +262,11 @@ namespace ServiceLib.Services
var item = await AppHandler.Instance.GetProfileItem(it.IndexId); var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
if (item is null) continue; if (item is null) continue;
WebProxy webProxy = new(Global.Loopback, it.Port); var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) => await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
{ {
decimal.TryParse(msg, out decimal dec); decimal.TryParse(msg, out var dec);
if (dec > 0) if (dec > 0)
{ {
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg); ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
@@ -249,28 +277,27 @@ namespace ServiceLib.Services
if (pid > 0) if (pid > 0)
{ {
CoreHandler.Instance.CoreStopPid(pid); await CoreHandler.Instance.CoreStopPid(pid);
} }
UpdateFunc("", ResUI.SpeedtestingCompleted);
await ProfileExHandler.Instance.SaveTo(); await ProfileExHandler.Instance.SaveTo();
} }
private async Task RunSpeedTestMulti() private async Task RunSpeedTestMulti(List<ServerTestItem> selecteds)
{ {
int pid = -1; var pid = -1;
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds); pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
if (pid < 0) if (pid < 0)
{ {
UpdateFunc("", ResUI.FailedToRunCore); UpdateFunc("", ResUI.FailedToRunCore);
return; return;
} }
string url = _config.SpeedTestItem.SpeedTestUrl; var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout; var timeout = _config.SpeedTestItem.SpeedTestTimeout;
DownloadService downloadHandle = new(); DownloadService downloadHandle = new();
foreach (var it in _selecteds) foreach (var it in selecteds)
{ {
if (_exitLoop) if (_exitLoop)
{ {
@@ -297,10 +324,10 @@ namespace ServiceLib.Services
var item = await AppHandler.Instance.GetProfileItem(it.IndexId); var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
if (item is null) continue; if (item is null) continue;
WebProxy webProxy = new(Global.Loopback, it.Port); var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) => _ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
{ {
decimal.TryParse(msg, out decimal dec); decimal.TryParse(msg, out var dec);
if (dec > 0) if (dec > 0)
{ {
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg); ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
@@ -314,38 +341,37 @@ namespace ServiceLib.Services
if (pid > 0) if (pid > 0)
{ {
CoreHandler.Instance.CoreStopPid(pid); await CoreHandler.Instance.CoreStopPid(pid);
} }
UpdateFunc("", ResUI.SpeedtestingCompleted);
await ProfileExHandler.Instance.SaveTo(); await ProfileExHandler.Instance.SaveTo();
} }
private async Task RunMixedtestAsync() private async Task RunMixedTestAsync(List<ServerTestItem> selecteds)
{ {
await RunRealPing(); await RunRealPingAsync(selecteds);
await Task.Delay(1000); await Task.Delay(1000);
await RunSpeedTestMulti(); await RunSpeedTestMulti(selecteds);
} }
private async Task<string> GetRealPingTime(DownloadService downloadHandle, IWebProxy webProxy) private async Task<string> GetRealPingTime(DownloadService downloadHandle, IWebProxy webProxy)
{ {
int responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10); var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
//string output = Utile.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);
} }
private async Task<int> GetTcpingTime(string url, int port) private async Task<int> GetTcpingTime(string url, int port)
{ {
int responseTime = -1; var responseTime = -1;
try try
{ {
if (!IPAddress.TryParse(url, out IPAddress? ipAddress)) if (!IPAddress.TryParse(url, out var ipAddress))
{ {
IPHostEntry ipHostInfo = Dns.GetHostEntry(url); var ipHostInfo = await Dns.GetHostEntryAsync(url);
ipAddress = ipHostInfo.AddressList[0]; ipAddress = ipHostInfo.AddressList.First();
} }
var timer = Stopwatch.StartNew(); var timer = Stopwatch.StartNew();

View File

@@ -8,8 +8,8 @@ namespace ServiceLib.Services.Statistics
private Config _config; private Config _config;
private bool _exitFlag; private bool _exitFlag;
private ClientWebSocket? webSocket; private ClientWebSocket? webSocket;
private string url = string.Empty;
private Action<ServerSpeedItem>? _updateFunc; private Action<ServerSpeedItem>? _updateFunc;
private string Url => $"ws://{Global.Loopback}:{AppHandler.Instance.StatePort2}/traffic";
public StatisticsSingboxService(Config config, Action<ServerSpeedItem> updateFunc) public StatisticsSingboxService(Config config, Action<ServerSpeedItem> updateFunc)
{ {
@@ -26,12 +26,10 @@ namespace ServiceLib.Services.Statistics
try try
{ {
url = $"ws://{Global.Loopback}:{AppHandler.Instance.StatePort2}/traffic";
if (webSocket == null) if (webSocket == null)
{ {
webSocket = new ClientWebSocket(); webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(url), CancellationToken.None); await webSocket.ConnectAsync(new Uri(Url), CancellationToken.None);
} }
} }
catch { } catch { }

View File

@@ -1,135 +0,0 @@
using Grpc.Core;
using Grpc.Net.Client;
using ProtosLib.Statistics;
namespace ServiceLib.Services.Statistics
{
public class StatisticsV2rayService
{
private Models.Config _config;
private GrpcChannel? _channel;
private StatsService.StatsServiceClient? _client;
private bool _exitFlag;
private Action<ServerSpeedItem>? _updateFunc;
public StatisticsV2rayService(Models.Config config, Action<ServerSpeedItem> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
_exitFlag = false;
GrpcInit();
Task.Run(Run);
}
private void GrpcInit()
{
if (_channel is null)
{
try
{
_channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort}");
_client = new StatsService.StatsServiceClient(_channel);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
}
public void Close()
{
_exitFlag = true;
}
private async void Run()
{
while (!_exitFlag)
{
await Task.Delay(1000);
try
{
if (!_config.IsRunningCore(ECoreType.Xray))
{
continue;
}
if (_channel?.State == ConnectivityState.Ready)
{
QueryStatsResponse? res = null;
try
{
if (_client != null)
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
}
catch
{
}
if (res != null)
{
ParseOutput(res.Stat, out ServerSpeedItem server);
_updateFunc?.Invoke(server);
}
}
if (_channel != null)
await _channel.ConnectAsync();
}
catch
{
}
}
}
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
{
server = new();
long aggregateProxyUp = 0;
long aggregateProxyDown = 0;
try
{
foreach (Stat stat in source)
{
string name = stat.Name;
long value = stat.Value / 1024; //KByte
string[] nStr = name.Split(">>>".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
string type = "";
name = name.Trim();
name = nStr[1];
type = nStr[3];
if (name.StartsWith(Global.ProxyTag))
{
if (type == "uplink")
{
aggregateProxyUp += value;
}
else if (type == "downlink")
{
aggregateProxyDown += value;
}
}
else if (name == Global.DirectTag)
{
if (type == "uplink")
{
server.DirectUp = value;
}
else if (type == "downlink")
{
server.DirectDown = value;
}
}
}
server.ProxyUp = aggregateProxyUp;
server.ProxyDown = aggregateProxyDown;
}
catch
{
}
}
}
}

View File

@@ -0,0 +1,105 @@
namespace ServiceLib.Services.Statistics
{
public class StatisticsXrayService
{
private const long linkBase = 1024;
private ServerSpeedItem _serverSpeedItem = new();
private Config _config;
private bool _exitFlag;
private Action<ServerSpeedItem>? _updateFunc;
private string Url => $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort}/debug/vars";
public StatisticsXrayService(Config config, Action<ServerSpeedItem> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
_exitFlag = false;
Task.Run(Run);
}
public void Close()
{
_exitFlag = true;
}
private async void Run()
{
while (!_exitFlag)
{
await Task.Delay(1000);
try
{
if (_config.RunningCoreType != ECoreType.Xray)
{
continue;
}
var result = await HttpClientHelper.Instance.TryGetAsync(Url);
if (result != null)
{
var server = ParseOutput(result) ?? new ServerSpeedItem();
_updateFunc?.Invoke(server);
}
}
catch
{
// ignored
}
}
}
private ServerSpeedItem? ParseOutput(string result)
{
try
{
var source = JsonUtils.Deserialize<V2rayMetricsVars>(result);
if (source?.stats?.outbound == null)
{
return null;
}
ServerSpeedItem server = new();
foreach (string key in source.stats.outbound.Keys)
{
var value = source.stats.outbound[key];
if (value == null) continue;
var state = JsonUtils.Deserialize<V2rayMetricsVarsLink>(value.ToString());
if (key.StartsWith(Global.ProxyTag))
{
server.ProxyUp += state.uplink / linkBase;
server.ProxyDown += state.downlink / linkBase;
}
else if (key == Global.DirectTag)
{
server.DirectUp = state.uplink / linkBase;
server.DirectDown = state.downlink / linkBase;
}
}
if (server.DirectDown < _serverSpeedItem.DirectDown || server.ProxyDown < _serverSpeedItem.ProxyDown)
{
_serverSpeedItem = new();
return null;
}
ServerSpeedItem curItem = new()
{
ProxyUp = server.ProxyUp - _serverSpeedItem.ProxyUp,
ProxyDown = server.ProxyDown - _serverSpeedItem.ProxyDown,
DirectUp = server.DirectUp - _serverSpeedItem.DirectUp,
DirectDown = server.DirectDown - _serverSpeedItem.DirectDown,
};
_serverSpeedItem = server;
return curItem;
}
catch
{
// ignored
}
return null;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace ServiceLib.Services namespace ServiceLib.Services
@@ -6,12 +6,10 @@ namespace ServiceLib.Services
public class UpdateService public class UpdateService
{ {
private Action<bool, string>? _updateFunc; private Action<bool, string>? _updateFunc;
private Config _config;
private int _timeout = 30; private int _timeout = 30;
public async Task CheckUpdateGuiN(Config config, Action<bool, string> updateFunc, bool preRelease) public async Task CheckUpdateGuiN(Config config, Action<bool, string> updateFunc, bool preRelease)
{ {
_config = config;
_updateFunc = updateFunc; _updateFunc = updateFunc;
var url = string.Empty; var url = string.Empty;
var fileName = string.Empty; var fileName = string.Empty;
@@ -53,7 +51,6 @@ namespace ServiceLib.Services
public async Task CheckUpdateCore(ECoreType type, Config config, Action<bool, string> updateFunc, bool preRelease) public async Task CheckUpdateCore(ECoreType type, Config config, Action<bool, string> updateFunc, bool preRelease)
{ {
_config = config;
_updateFunc = updateFunc; _updateFunc = updateFunc;
var url = string.Empty; var url = string.Empty;
var fileName = string.Empty; var fileName = string.Empty;
@@ -108,13 +105,12 @@ namespace ServiceLib.Services
public async Task UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> updateFunc) public async Task UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> updateFunc)
{ {
_config = config;
_updateFunc = updateFunc; _updateFunc = updateFunc;
_updateFunc?.Invoke(false, ResUI.MsgUpdateSubscriptionStart); _updateFunc?.Invoke(false, ResUI.MsgUpdateSubscriptionStart);
var subItem = await AppHandler.Instance.SubItems(); var subItem = await AppHandler.Instance.SubItems();
if (subItem == null || subItem.Count <= 0) if (subItem is not { Count: > 0 })
{ {
_updateFunc?.Invoke(false, ResUI.MsgNoValidSubscription); _updateFunc?.Invoke(false, ResUI.MsgNoValidSubscription);
return; return;
@@ -122,11 +118,11 @@ namespace ServiceLib.Services
foreach (var item in subItem) foreach (var item in subItem)
{ {
string id = item.Id.TrimEx(); var id = item.Id.TrimEx();
string url = item.Url.TrimEx(); var url = item.Url.TrimEx();
string userAgent = item.UserAgent.TrimEx(); var userAgent = item.UserAgent.TrimEx();
string hashCode = $"{item.Remarks}->"; var hashCode = $"{item.Remarks}->";
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || Utils.IsNotEmpty(subId) && item.Id != subId) if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (Utils.IsNotEmpty(subId) && item.Id != subId))
{ {
//_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgNoValidSubscription}"); //_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
continue; continue;
@@ -219,7 +215,7 @@ namespace ServiceLib.Services
_updateFunc?.Invoke(false, $"{hashCode}{result}"); _updateFunc?.Invoke(false, $"{hashCode}{result}");
} }
int ret = await ConfigHandler.AddBatchServers(config, result, id, true); var ret = await ConfigHandler.AddBatchServers(config, result, id, true);
if (ret <= 0) if (ret <= 0)
{ {
Logging.SaveLog("FailedImportSubscription"); Logging.SaveLog("FailedImportSubscription");
@@ -231,6 +227,8 @@ namespace ServiceLib.Services
: $"{hashCode}{ResUI.MsgFailedImportSubscription}"); : $"{hashCode}{ResUI.MsgFailedImportSubscription}");
} }
_updateFunc?.Invoke(false, "-------------------------------------------------------"); _updateFunc?.Invoke(false, "-------------------------------------------------------");
//await ConfigHandler.DedupServerList(config, id);
} }
_updateFunc?.Invoke(true, $"{ResUI.MsgUpdateSubscriptionEnd}"); _updateFunc?.Invoke(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
@@ -246,8 +244,17 @@ namespace ServiceLib.Services
public async Task RunAvailabilityCheck(Action<bool, string> updateFunc) public async Task RunAvailabilityCheck(Action<bool, string> updateFunc)
{ {
var time = await new DownloadService().RunAvailabilityCheck(null); var downloadHandle = new DownloadService();
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time)); var time = await downloadHandle.RunAvailabilityCheck(null);
var ip = Global.None;
if (time > 0)
{
var result = await downloadHandle.TryDownloadString(Global.IPAPIUrl, true, Global.IPAPIUrl);
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
ip = $"({ipInfo?.country_code}) {ipInfo?.ip}";
}
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time, ip));
} }
#region CheckUpdate private #region CheckUpdate private
@@ -443,6 +450,15 @@ namespace ServiceLib.Services
_ => null, _ => null,
}; };
} }
else if (Utils.IsOSX())
{
return RuntimeInformation.ProcessArchitecture switch
{
Architecture.Arm64 => coreInfo?.DownloadUrlOSXArm64,
Architecture.X64 => coreInfo?.DownloadUrlOSX64,
_ => null,
};
}
return null; return null;
} }
@@ -452,7 +468,6 @@ namespace ServiceLib.Services
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> updateFunc) private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> updateFunc)
{ {
_config = config;
_updateFunc = updateFunc; _updateFunc = updateFunc;
var geoUrl = string.IsNullOrEmpty(config?.ConstItem.GeoSourceUrl) var geoUrl = string.IsNullOrEmpty(config?.ConstItem.GeoSourceUrl)
@@ -468,7 +483,6 @@ namespace ServiceLib.Services
private async Task UpdateSrsFileAll(Config config, Action<bool, string> updateFunc) private async Task UpdateSrsFileAll(Config config, Action<bool, string> updateFunc)
{ {
_config = config;
_updateFunc = updateFunc; _updateFunc = updateFunc;
var geoipFiles = new List<string>(); var geoipFiles = new List<string>();
@@ -519,9 +533,9 @@ namespace ServiceLib.Services
private async Task UpdateSrsFile(string type, string srsName, Config config, Action<bool, string> updateFunc) private async Task UpdateSrsFile(string type, string srsName, Config config, Action<bool, string> updateFunc)
{ {
var srsUrl = string.IsNullOrEmpty(_config.ConstItem.SrsSourceUrl) var srsUrl = string.IsNullOrEmpty(config.ConstItem.SrsSourceUrl)
? Global.SingboxRulesetUrl ? Global.SingboxRulesetUrl
: _config.ConstItem.SrsSourceUrl; : config.ConstItem.SrsSourceUrl;
var fileName = $"{type}-{srsName}.srs"; var fileName = $"{type}-{srsName}.srs";
var targetPath = Path.Combine(Utils.GetBinPath("srss"), fileName); var targetPath = Path.Combine(Utils.GetBinPath("srss"), fileName);

View File

@@ -160,9 +160,9 @@ namespace ServiceLib.ViewModels
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}"); var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs); var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs);
await Task.Run(() => FileManager.CopyDirectory(configDir, configDirTemp, false, "cache.db")); FileManager.CopyDirectory(configDir, configDirTemp, false, "cache.db");
var ret = await Task.Run(() => FileManager.CreateFromDirectory(configDirZipTemp, fileName)); var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName);
await Task.Run(() => Directory.Delete(configDirZipTemp, true)); Directory.Delete(configDirZipTemp, true);
return ret; return ret;
} }
} }

View File

@@ -12,10 +12,10 @@ namespace ServiceLib.ViewModels
{ {
private const string _geo = "GeoFiles"; private const string _geo = "GeoFiles";
private string _v2rayN = ECoreType.v2rayN.ToString(); private string _v2rayN = ECoreType.v2rayN.ToString();
private List<CheckUpdateItem> _lstUpdated = []; private List<CheckUpdateModel> _lstUpdated = [];
private IObservableCollection<CheckUpdateItem> _checkUpdateItem = new ObservableCollectionExtended<CheckUpdateItem>(); private IObservableCollection<CheckUpdateModel> _checkUpdateModel = new ObservableCollectionExtended<CheckUpdateModel>();
public IObservableCollection<CheckUpdateItem> CheckUpdateItems => _checkUpdateItem; public IObservableCollection<CheckUpdateModel> CheckUpdateModels => _checkUpdateModel;
public ReactiveCommand<Unit, Unit> CheckUpdateCmd { get; } public ReactiveCommand<Unit, Unit> CheckUpdateCmd { get; }
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; } [Reactive] public bool EnableCheckPreReleaseUpdate { get; set; }
@@ -29,65 +29,56 @@ namespace ServiceLib.ViewModels
await CheckUpdate(); await CheckUpdate();
}); });
EnableCheckPreReleaseUpdate = _config.GuiItem.CheckPreReleaseUpdate; EnableCheckPreReleaseUpdate = _config.CheckUpdateItem.CheckPreReleaseUpdate;
this.WhenAnyValue( this.WhenAnyValue(
x => x.EnableCheckPreReleaseUpdate, x => x.EnableCheckPreReleaseUpdate,
y => y == true) y => y == true)
.Subscribe(c => { _config.GuiItem.CheckPreReleaseUpdate = EnableCheckPreReleaseUpdate; }); .Subscribe(c => { _config.CheckUpdateItem.CheckPreReleaseUpdate = EnableCheckPreReleaseUpdate; });
RefreshSubItems(); RefreshCheckUpdateItems();
} }
private void RefreshSubItems() private void RefreshCheckUpdateItems()
{ {
_checkUpdateItem.Clear(); _checkUpdateModel.Clear();
if (RuntimeInformation.ProcessArchitecture != Architecture.X86) if (RuntimeInformation.ProcessArchitecture != Architecture.X86)
{ {
_checkUpdateItem.Add(new CheckUpdateItem() _checkUpdateModel.Add(GetCheckUpdateModel(_v2rayN));
{ _checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.Xray.ToString()));
IsSelected = false, _checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.mihomo.ToString()));
CoreType = _v2rayN, _checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.sing_box.ToString()));
Remarks = ResUI.menuCheckUpdate,
});
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = true,
CoreType = ECoreType.Xray.ToString(),
Remarks = ResUI.menuCheckUpdate,
});
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = true,
CoreType = ECoreType.mihomo.ToString(),
Remarks = ResUI.menuCheckUpdate,
});
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = true,
CoreType = ECoreType.sing_box.ToString(),
Remarks = ResUI.menuCheckUpdate,
});
} }
_checkUpdateModel.Add(GetCheckUpdateModel(_geo));
}
_checkUpdateItem.Add(new CheckUpdateItem() private CheckUpdateModel GetCheckUpdateModel(string coreType)
{
return new()
{ {
IsSelected = true, IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType) ?? true,
CoreType = _geo, CoreType = coreType,
Remarks = ResUI.menuCheckUpdate, Remarks = ResUI.menuCheckUpdate,
}); };
}
private async Task SaveSelectedCoreTypes()
{
_config.CheckUpdateItem.SelectedCoreTypes = _checkUpdateModel.Where(t => t.IsSelected == true).Select(t => t.CoreType ?? "").ToList();
await ConfigHandler.SaveConfig(_config);
} }
private async Task CheckUpdate() private async Task CheckUpdate()
{ {
_lstUpdated.Clear(); _lstUpdated.Clear();
_lstUpdated = _checkUpdateItem.Where(x => x.IsSelected == true) _lstUpdated = _checkUpdateModel.Where(x => x.IsSelected == true)
.Select(x => new CheckUpdateItem() { CoreType = x.CoreType }).ToList(); .Select(x => new CheckUpdateModel() { CoreType = x.CoreType }).ToList();
await SaveSelectedCoreTypes();
for (var k = _checkUpdateItem.Count - 1; k >= 0; k--) for (var k = _checkUpdateModel.Count - 1; k >= 0; k--)
{ {
var item = _checkUpdateItem[k]; var item = _checkUpdateModel[k];
if (item.IsSelected != true) continue; if (item.IsSelected != true) continue;
UpdateView(item.CoreType, "..."); UpdateView(item.CoreType, "...");
@@ -99,13 +90,13 @@ namespace ServiceLib.ViewModels
{ {
await CheckUpdateN(EnableCheckPreReleaseUpdate); await CheckUpdateN(EnableCheckPreReleaseUpdate);
} }
else if (item.CoreType == ECoreType.mihomo.ToString()) else if (item.CoreType == ECoreType.Xray.ToString())
{ {
await CheckUpdateCore(item, false); await CheckUpdateCore(item, EnableCheckPreReleaseUpdate);
} }
else else
{ {
await CheckUpdateCore(item, EnableCheckPreReleaseUpdate); await CheckUpdateCore(item, false);
} }
} }
@@ -161,23 +152,23 @@ namespace ServiceLib.ViewModels
}); });
} }
private async Task CheckUpdateCore(CheckUpdateItem item, bool preRelease) private async Task CheckUpdateCore(CheckUpdateModel model, bool preRelease)
{ {
void _updateUI(bool success, string msg) void _updateUI(bool success, string msg)
{ {
UpdateView(item.CoreType, msg); UpdateView(model.CoreType, msg);
if (success) if (success)
{ {
UpdateView(item.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore); UpdateView(model.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
UpdatedPlusPlus(item.CoreType, msg); UpdatedPlusPlus(model.CoreType, msg);
} }
} }
var type = (ECoreType)Enum.Parse(typeof(ECoreType), item.CoreType); var type = (ECoreType)Enum.Parse(typeof(ECoreType), model.CoreType);
await (new UpdateService()).CheckUpdateCore(type, _config, _updateUI, preRelease) await (new UpdateService()).CheckUpdateCore(type, _config, _updateUI, preRelease)
.ContinueWith(t => .ContinueWith(t =>
{ {
UpdatedPlusPlus(item.CoreType, ""); UpdatedPlusPlus(model.CoreType, "");
}); });
} }
@@ -271,12 +262,12 @@ namespace ServiceLib.ViewModels
FileManager.ZipExtractToFile(fileName, toPath, _config.GuiItem.IgnoreGeoUpdateCore ? "geo" : ""); FileManager.ZipExtractToFile(fileName, toPath, _config.GuiItem.IgnoreGeoUpdateCore ? "geo" : "");
} }
if (Utils.IsLinux()) if (Utils.IsNonWindows())
{ {
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList(); var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
foreach (var file in filesList) foreach (var file in filesList)
{ {
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType)); await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType.ToLower()));
} }
} }
@@ -291,7 +282,7 @@ namespace ServiceLib.ViewModels
private void UpdateView(string coreType, string msg) private void UpdateView(string coreType, string msg)
{ {
var item = new CheckUpdateItem() var item = new CheckUpdateModel()
{ {
CoreType = coreType, CoreType = coreType,
Remarks = msg, Remarks = msg,
@@ -299,13 +290,13 @@ namespace ServiceLib.ViewModels
_updateView?.Invoke(EViewAction.DispatcherCheckUpdate, item); _updateView?.Invoke(EViewAction.DispatcherCheckUpdate, item);
} }
public void UpdateViewResult(CheckUpdateItem item) public void UpdateViewResult(CheckUpdateModel model)
{ {
var found = _checkUpdateItem.FirstOrDefault(t => t.CoreType == item.CoreType); var found = _checkUpdateModel.FirstOrDefault(t => t.CoreType == model.CoreType);
if (found == null) return; if (found == null) return;
var itemCopy = JsonUtils.DeepCopy(found); var itemCopy = JsonUtils.DeepCopy(found);
itemCopy.Remarks = item.Remarks; itemCopy.Remarks = model.Remarks;
_checkUpdateItem.Replace(found, itemCopy); _checkUpdateModel.Replace(found, itemCopy);
} }
} }
} }

View File

@@ -21,9 +21,6 @@ namespace ServiceLib.ViewModels
[Reactive] [Reactive]
public string HostFilter { get; set; } public string HostFilter { get; set; }
[Reactive]
public int SortingSelected { get; set; }
[Reactive] [Reactive]
public bool AutoRefresh { get; set; } public bool AutoRefresh { get; set; }
@@ -31,18 +28,12 @@ namespace ServiceLib.ViewModels
{ {
_config = AppHandler.Instance.Config; _config = AppHandler.Instance.Config;
_updateView = updateView; _updateView = updateView;
SortingSelected = _config.ClashUIItem.ConnectionsSorting;
AutoRefresh = _config.ClashUIItem.ConnectionsAutoRefresh; AutoRefresh = _config.ClashUIItem.ConnectionsAutoRefresh;
var canEditRemove = this.WhenAnyValue( var canEditRemove = this.WhenAnyValue(
x => x.SelectedSource, x => x.SelectedSource,
selectedSource => selectedSource != null && Utils.IsNotEmpty(selectedSource.Id)); selectedSource => selectedSource != null && Utils.IsNotEmpty(selectedSource.Id));
this.WhenAnyValue(
x => x.SortingSelected,
y => y >= 0)
.Subscribe(async c => await DoSortingSelected(c));
this.WhenAnyValue( this.WhenAnyValue(
x => x.AutoRefresh, x => x.AutoRefresh,
y => y == true) y => y == true)
@@ -84,20 +75,6 @@ namespace ServiceLib.ViewModels
}); });
} }
private async Task DoSortingSelected(bool c)
{
if (!c)
{
return;
}
if (SortingSelected != _config.ClashUIItem.ConnectionsSorting)
{
_config.ClashUIItem.ConnectionsSorting = SortingSelected;
}
await GetClashConnections();
}
private async Task GetClashConnections() private async Task GetClashConnections()
{ {
var ret = await ClashApiHandler.Instance.GetClashConnectionsAsync(_config); var ret = await ClashApiHandler.Instance.GetClashConnectionsAsync(_config);
@@ -115,7 +92,7 @@ namespace ServiceLib.ViewModels
var dtNow = DateTime.Now; var dtNow = DateTime.Now;
var lstModel = new List<ClashConnectionModel>(); var lstModel = new List<ClashConnectionModel>();
foreach (var item in connections ?? []) foreach (var item in connections ?? new())
{ {
var host = $"{(Utils.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}"; var host = $"{(Utils.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}";
if (HostFilter.IsNotEmpty() && !host.Contains(HostFilter)) if (HostFilter.IsNotEmpty() && !host.Contains(HostFilter))
@@ -131,45 +108,14 @@ namespace ServiceLib.ViewModels
model.Host = host; model.Host = host;
var sp = (dtNow - item.start); var sp = (dtNow - item.start);
model.Time = sp.TotalSeconds < 0 ? 1 : sp.TotalSeconds; model.Time = sp.TotalSeconds < 0 ? 1 : sp.TotalSeconds;
model.Upload = item.upload;
model.Download = item.download;
model.UploadTraffic = $"{Utils.HumanFy((long)item.upload)}";
model.DownloadTraffic = $"{Utils.HumanFy((long)item.download)}";
model.Elapsed = sp.ToString(@"hh\:mm\:ss"); model.Elapsed = sp.ToString(@"hh\:mm\:ss");
model.Chain = item.chains?.Count > 0 ? item.chains[0] : string.Empty; item.chains?.Reverse();
model.Chain = $"{item.rule} , {string.Join("->", item.chains ?? new())}";
lstModel.Add(model); lstModel.Add(model);
} }
if (lstModel.Count <= 0) { return; } if (lstModel.Count <= 0) { return; }
//sort
switch (SortingSelected)
{
case 0:
lstModel = lstModel.OrderBy(t => t.Upload / t.Time).ToList();
break;
case 1:
lstModel = lstModel.OrderBy(t => t.Download / t.Time).ToList();
break;
case 2:
lstModel = lstModel.OrderBy(t => t.Upload).ToList();
break;
case 3:
lstModel = lstModel.OrderBy(t => t.Download).ToList();
break;
case 4:
lstModel = lstModel.OrderBy(t => t.Time).ToList();
break;
case 5:
lstModel = lstModel.OrderBy(t => t.Host).ToList();
break;
}
_connectionItems.AddRange(lstModel); _connectionItems.AddRange(lstModel);
} }

View File

@@ -239,7 +239,7 @@ namespace ServiceLib.ViewModels
} }
else else
{ {
SelectedGroup = _proxyGroups[0]; SelectedGroup = _proxyGroups.First();
} }
} }
else else

View File

@@ -1,4 +1,4 @@
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System.Reactive; using System.Reactive;
@@ -105,7 +105,7 @@ namespace ServiceLib.ViewModels
item2.DomainStrategy4Freedom = domainStrategy4Freedom2; item2.DomainStrategy4Freedom = domainStrategy4Freedom2;
item2.DomainDNSAddress = domainDNSAddress2; item2.DomainDNSAddress = domainDNSAddress2;
item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(normalDNS2)); item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(normalDNS2));
item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2)); ; item2.TunDNS = JsonUtils.Serialize(JsonUtils.ParseJson(tunDNS2));
await ConfigHandler.SaveDNSItems(_config, item2); await ConfigHandler.SaveDNSItems(_config, item2);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);

View File

@@ -50,6 +50,8 @@ namespace ServiceLib.ViewModels
public ReactiveCommand<Unit, Unit> RegionalPresetRussiaCmd { get; } public ReactiveCommand<Unit, Unit> RegionalPresetRussiaCmd { get; }
public ReactiveCommand<Unit, Unit> RegionalPresetIranCmd { get; }
public ReactiveCommand<Unit, Unit> ReloadCmd { get; } public ReactiveCommand<Unit, Unit> ReloadCmd { get; }
[Reactive] [Reactive]
@@ -197,6 +199,11 @@ namespace ServiceLib.ViewModels
await ApplyRegionalPreset(EPresetType.Russia); await ApplyRegionalPreset(EPresetType.Russia);
}); });
RegionalPresetIranCmd = ReactiveCommand.CreateFromTask(async () =>
{
await ApplyRegionalPreset(EPresetType.Iran);
});
#endregion WhenAnyValue && ReactiveCommand #endregion WhenAnyValue && ReactiveCommand
Init(); Init();
@@ -219,6 +226,7 @@ namespace ServiceLib.ViewModels
await Reload(); await Reload();
await AutoHideStartup(); await AutoHideStartup();
Locator.Current.GetService<StatusBarViewModel>()?.RefreshRoutingsMenu();
} }
#endregion Init #endregion Init
@@ -266,7 +274,7 @@ namespace ServiceLib.ViewModels
try try
{ {
Locator.Current.GetService<StatusBarViewModel>()?.UpdateStatistics(update); Locator.Current.GetService<StatusBarViewModel>()?.UpdateStatistics(update);
if ((update.ProxyUp + update.ProxyDown) > 0 && DateTime.Now.Second % 3 == 0) if ((update.ProxyUp + update.ProxyDown) > 0 && DateTime.Now.Second % 9 == 0)
{ {
Locator.Current.GetService<ProfilesViewModel>()?.UpdateStatistics(update); Locator.Current.GetService<ProfilesViewModel>()?.UpdateStatistics(update);
} }
@@ -281,22 +289,25 @@ namespace ServiceLib.ViewModels
{ {
try try
{ {
Logging.SaveLog("MyAppExit Begin"); Logging.SaveLog("MyAppExitAsync Begin");
//if (blWindowsShutDown) MessageBus.Current.SendMessage("", EMsgCommand.AppExit.ToString());
await SysProxyHandler.UpdateSysProxy(_config, true);
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
await SysProxyHandler.UpdateSysProxy(_config, true);
await ProfileExHandler.Instance.SaveTo(); await ProfileExHandler.Instance.SaveTo();
await StatisticsHandler.Instance.SaveTo(); await StatisticsHandler.Instance.SaveTo();
StatisticsHandler.Instance.Close(); StatisticsHandler.Instance.Close();
CoreHandler.Instance.CoreStop(); await CoreHandler.Instance.CoreStop();
Logging.SaveLog("MyAppExit End"); Logging.SaveLog("MyAppExitAsync End");
} }
catch { } catch { }
finally finally
{ {
_updateView?.Invoke(EViewAction.Shutdown, null); if (!blWindowsShutDown)
{
_updateView?.Invoke(EViewAction.Shutdown, null);
}
} }
} }
@@ -323,6 +334,7 @@ namespace ServiceLib.ViewModels
if (process.Id > 0) if (process.Id > 0)
{ {
await MyAppExitAsync(false); await MyAppExitAsync(false);
await MyAppExitAsync(false);
} }
} }
@@ -523,13 +535,18 @@ namespace ServiceLib.ViewModels
private async Task OpenTheFileLocation() private async Task OpenTheFileLocation()
{ {
var path = Utils.StartupPath();
if (Utils.IsWindows()) if (Utils.IsWindows())
{ {
Utils.ProcessStart("Explorer", $"/select,{Utils.GetConfigPath()}"); Utils.ProcessStart(path);
} }
else if (Utils.IsLinux()) else if (Utils.IsLinux())
{ {
Utils.ProcessStart("nautilus", Utils.GetConfigPath()); Utils.ProcessStart("nautilus", path);
}
else if (Utils.IsOSX())
{
Utils.ProcessStart("open", path);
} }
} }

View File

@@ -9,7 +9,6 @@ namespace ServiceLib.ViewModels
{ {
private ConcurrentQueue<string> _queueMsg = new(); private ConcurrentQueue<string> _queueMsg = new();
private int _numMaxMsg = 500; private int _numMaxMsg = 500;
private string _lastMsgFilter = string.Empty;
private bool _lastMsgFilterNotAvailable; private bool _lastMsgFilterNotAvailable;
private bool _blLockShow = false; private bool _blLockShow = false;
@@ -28,7 +27,7 @@ namespace ServiceLib.ViewModels
this.WhenAnyValue( this.WhenAnyValue(
x => x.MsgFilter) x => x.MsgFilter)
.Subscribe(c => _config.MsgUIItem.MainMsgFilter = MsgFilter); .Subscribe(c => DoMsgFilter());
this.WhenAnyValue( this.WhenAnyValue(
x => x.AutoRefresh, x => x.AutoRefresh,
@@ -77,8 +76,7 @@ namespace ServiceLib.ViewModels
private async Task EnqueueQueueMsg(string msg) private async Task EnqueueQueueMsg(string msg)
{ {
//filter msg //filter msg
if (MsgFilter != _lastMsgFilter) _lastMsgFilterNotAvailable = false; if (MsgFilter.IsNotEmpty() && !_lastMsgFilterNotAvailable)
if (Utils.IsNotEmpty(MsgFilter) && !_lastMsgFilterNotAvailable)
{ {
try try
{ {
@@ -87,12 +85,12 @@ namespace ServiceLib.ViewModels
return; return;
} }
} }
catch (Exception) catch (Exception ex)
{ {
_queueMsg.Enqueue(ex.Message);
_lastMsgFilterNotAvailable = true; _lastMsgFilterNotAvailable = true;
} }
} }
_lastMsgFilter = MsgFilter;
//Enqueue //Enqueue
if (_queueMsg.Count > _numMaxMsg) if (_queueMsg.Count > _numMaxMsg)
@@ -113,5 +111,11 @@ namespace ServiceLib.ViewModels
{ {
_queueMsg.Clear(); _queueMsg.Clear();
} }
private void DoMsgFilter()
{
_config.MsgUIItem.MainMsgFilter = MsgFilter;
_lastMsgFilterNotAvailable = false;
}
} }
} }

View File

@@ -9,6 +9,7 @@ namespace ServiceLib.ViewModels
#region Core #region Core
[Reactive] public int localPort { get; set; } [Reactive] public int localPort { get; set; }
[Reactive] public bool SecondLocalPortEnabled { get; set; }
[Reactive] public bool udpEnabled { get; set; } [Reactive] public bool udpEnabled { get; set; }
[Reactive] public bool sniffingEnabled { get; set; } [Reactive] public bool sniffingEnabled { get; set; }
public IList<string> destOverride { get; set; } public IList<string> destOverride { get; set; }
@@ -53,7 +54,7 @@ namespace ServiceLib.ViewModels
[Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; } [Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; }
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; } [Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
[Reactive] public bool AutoHideStartup { get; set; } [Reactive] public bool AutoHideStartup { get; set; }
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; } [Reactive] public bool Hide2TrayWhenClose { get; set; }
[Reactive] public bool EnableDragDropSort { get; set; } [Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; } [Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int AutoUpdateInterval { get; set; } [Reactive] public int AutoUpdateInterval { get; set; }
@@ -62,6 +63,7 @@ namespace ServiceLib.ViewModels
[Reactive] public int SpeedTestTimeout { get; set; } [Reactive] public int SpeedTestTimeout { get; set; }
[Reactive] public string SpeedTestUrl { get; set; } [Reactive] public string SpeedTestUrl { get; set; }
[Reactive] public string SpeedPingTestUrl { get; set; } [Reactive] public string SpeedPingTestUrl { get; set; }
[Reactive] public int SpeedTestPageSize { get; set; }
[Reactive] public bool EnableHWA { get; set; } [Reactive] public bool EnableHWA { get; set; }
[Reactive] public string SubConvertUrl { get; set; } [Reactive] public string SubConvertUrl { get; set; }
[Reactive] public int MainGirdOrientation { get; set; } [Reactive] public int MainGirdOrientation { get; set; }
@@ -86,6 +88,7 @@ namespace ServiceLib.ViewModels
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
[Reactive] public bool TunEnableExInbound { get; set; } [Reactive] public bool TunEnableExInbound { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; } [Reactive] public bool TunEnableIPv6Address { get; set; }
[Reactive] public string TunLinuxSudoPassword { get; set; }
#endregion Tun mode #endregion Tun mode
@@ -121,8 +124,9 @@ namespace ServiceLib.ViewModels
#region Core #region Core
var inbound = _config.Inbound[0]; var inbound = _config.Inbound.First();
localPort = inbound.LocalPort; localPort = inbound.LocalPort;
SecondLocalPortEnabled = inbound.SecondLocalPortEnabled;
udpEnabled = inbound.UdpEnabled; udpEnabled = inbound.UdpEnabled;
sniffingEnabled = inbound.SniffingEnabled; sniffingEnabled = inbound.SniffingEnabled;
routeOnly = inbound.RouteOnly; routeOnly = inbound.RouteOnly;
@@ -166,7 +170,7 @@ namespace ServiceLib.ViewModels
EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist; EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist;
EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13; EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13;
AutoHideStartup = _config.UiItem.AutoHideStartup; AutoHideStartup = _config.UiItem.AutoHideStartup;
EnableCheckPreReleaseUpdate = _config.GuiItem.CheckPreReleaseUpdate; Hide2TrayWhenClose = _config.UiItem.Hide2TrayWhenClose;
EnableDragDropSort = _config.UiItem.EnableDragDropSort; EnableDragDropSort = _config.UiItem.EnableDragDropSort;
DoubleClick2Activate = _config.UiItem.DoubleClick2Activate; DoubleClick2Activate = _config.UiItem.DoubleClick2Activate;
AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval; AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval;
@@ -174,6 +178,7 @@ namespace ServiceLib.ViewModels
CurrentFontFamily = _config.UiItem.CurrentFontFamily; CurrentFontFamily = _config.UiItem.CurrentFontFamily;
SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout; SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout;
SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl; SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl;
SpeedTestPageSize = _config.SpeedTestItem.SpeedTestPageSize;
SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl; SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl;
EnableHWA = _config.GuiItem.EnableHWA; EnableHWA = _config.GuiItem.EnableHWA;
SubConvertUrl = _config.ConstItem.SubConvertUrl; SubConvertUrl = _config.ConstItem.SubConvertUrl;
@@ -199,6 +204,7 @@ namespace ServiceLib.ViewModels
TunMtu = _config.TunModeItem.Mtu; TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound; TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address; TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
#endregion Tun mode #endregion Tun mode
@@ -283,15 +289,16 @@ namespace ServiceLib.ViewModels
//} //}
//Core //Core
_config.Inbound[0].LocalPort = localPort; _config.Inbound.First().LocalPort = localPort;
_config.Inbound[0].UdpEnabled = udpEnabled; _config.Inbound.First().SecondLocalPortEnabled = SecondLocalPortEnabled;
_config.Inbound[0].SniffingEnabled = sniffingEnabled; _config.Inbound.First().UdpEnabled = udpEnabled;
_config.Inbound[0].DestOverride = destOverride?.ToList(); _config.Inbound.First().SniffingEnabled = sniffingEnabled;
_config.Inbound[0].RouteOnly = routeOnly; _config.Inbound.First().DestOverride = destOverride?.ToList();
_config.Inbound[0].AllowLANConn = allowLANConn; _config.Inbound.First().RouteOnly = routeOnly;
_config.Inbound[0].NewPort4LAN = newPort4LAN; _config.Inbound.First().AllowLANConn = allowLANConn;
_config.Inbound[0].User = user; _config.Inbound.First().NewPort4LAN = newPort4LAN;
_config.Inbound[0].Pass = pass; _config.Inbound.First().User = user;
_config.Inbound.First().Pass = pass;
if (_config.Inbound.Count > 1) if (_config.Inbound.Count > 1)
{ {
_config.Inbound.RemoveAt(1); _config.Inbound.RemoveAt(1);
@@ -316,13 +323,14 @@ namespace ServiceLib.ViewModels
_config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist; _config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist;
_config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13; _config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.UiItem.AutoHideStartup = AutoHideStartup; _config.UiItem.AutoHideStartup = AutoHideStartup;
_config.UiItem.Hide2TrayWhenClose = Hide2TrayWhenClose;
_config.GuiItem.AutoUpdateInterval = AutoUpdateInterval; _config.GuiItem.AutoUpdateInterval = AutoUpdateInterval;
_config.GuiItem.CheckPreReleaseUpdate = EnableCheckPreReleaseUpdate;
_config.UiItem.EnableDragDropSort = EnableDragDropSort; _config.UiItem.EnableDragDropSort = EnableDragDropSort;
_config.UiItem.DoubleClick2Activate = DoubleClick2Activate; _config.UiItem.DoubleClick2Activate = DoubleClick2Activate;
_config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit; _config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit;
_config.UiItem.CurrentFontFamily = CurrentFontFamily; _config.UiItem.CurrentFontFamily = CurrentFontFamily;
_config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout; _config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout;
_config.SpeedTestItem.SpeedTestPageSize = SpeedTestPageSize;
_config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl; _config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl;
_config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl; _config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl;
_config.GuiItem.EnableHWA = EnableHWA; _config.GuiItem.EnableHWA = EnableHWA;
@@ -343,20 +351,20 @@ namespace ServiceLib.ViewModels
_config.TunModeItem.Mtu = TunMtu; _config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound; _config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address; _config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
{
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
}
//coreType //coreType
await SaveCoreType(); await SaveCoreType();
if (await ConfigHandler.SaveConfig(_config) == 0) if (await ConfigHandler.SaveConfig(_config) == 0)
{ {
if (needReboot) await AutoStartupHandler.UpdateTask(_config);
{ AppHandler.Instance.Reset();
NoticeHandler.Instance.Enqueue(ResUI.NeedRebootTips);
} NoticeHandler.Instance.Enqueue(needReboot ? ResUI.NeedRebootTips : ResUI.OperationSuccess);
else
{
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
}
_updateView?.Invoke(EViewAction.CloseWindow, null); _updateView?.Invoke(EViewAction.CloseWindow, null);
} }
else else

View File

@@ -16,7 +16,6 @@ namespace ServiceLib.ViewModels
private List<ProfileItem> _lstProfile; private List<ProfileItem> _lstProfile;
private string _serverFilter = string.Empty; private string _serverFilter = string.Empty;
private Dictionary<string, bool> _dicHeaderSort = new(); private Dictionary<string, bool> _dicHeaderSort = new();
private SpeedtestService? _speedtestHandler;
#endregion private prop #endregion private prop
@@ -375,7 +374,7 @@ namespace ServiceLib.ViewModels
} }
else else
{ {
SelectedProfile = lstModel[0]; SelectedProfile = lstModel.First();
} }
} }
} }
@@ -396,7 +395,7 @@ namespace ServiceLib.ViewModels
} }
else else
{ {
SelectedSub = _subItems[0]; SelectedSub = _subItems.First();
} }
} }
@@ -480,7 +479,10 @@ namespace ServiceLib.ViewModels
await ConfigHandler.RemoveServer(_config, lstSelecteds); await ConfigHandler.RemoveServer(_config, lstSelecteds);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
if (lstSelecteds.Count == _profileItems.Count)
{
_profileItems.Clear();
}
RefreshServers(); RefreshServers();
if (exists) if (exists)
{ {
@@ -637,6 +639,7 @@ namespace ServiceLib.ViewModels
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
RefreshServers(); RefreshServers();
SelectedMoveToGroup = null;
SelectedMoveToGroup = new(); SelectedMoveToGroup = new();
//Reload(); //Reload();
} }
@@ -686,12 +689,12 @@ namespace ServiceLib.ViewModels
} }
//ClearTestResult(); //ClearTestResult();
_speedtestHandler = new SpeedtestService(_config, lstSelecteds, actionType, UpdateSpeedtestHandler); _ = new SpeedtestService(_config, lstSelecteds, actionType, UpdateSpeedtestHandler);
} }
public void ServerSpeedtestStop() public void ServerSpeedtestStop()
{ {
_speedtestHandler?.ExitLoop(); MessageBus.Current.SendMessage("", EMsgCommand.StopSpeedtest.ToString());
} }
private async Task Export2ClientConfigAsync(bool blClipboard) private async Task Export2ClientConfigAsync(bool blClipboard)
@@ -727,7 +730,7 @@ namespace ServiceLib.ViewModels
{ {
return; return;
} }
var result = await CoreConfigHandler.GenerateClientConfig(item, null); var result = await CoreConfigHandler.GenerateClientConfig(item, fileName);
if (result.Success != true) if (result.Success != true)
{ {
NoticeHandler.Instance.Enqueue(result.Msg); NoticeHandler.Instance.Enqueue(result.Msg);

View File

@@ -74,19 +74,20 @@ namespace ServiceLib.ViewModels
SelectedSource.Protocol = ProtocolItems?.ToList(); SelectedSource.Protocol = ProtocolItems?.ToList();
SelectedSource.InboundTag = InboundTagItems?.ToList(); SelectedSource.InboundTag = InboundTagItems?.ToList();
bool hasRule = SelectedSource.Domain?.Count > 0 var hasRule = SelectedSource.Domain?.Count > 0
|| SelectedSource.Ip?.Count > 0 || SelectedSource.Ip?.Count > 0
|| SelectedSource.Protocol?.Count > 0 || SelectedSource.Protocol?.Count > 0
|| SelectedSource.Process?.Count > 0 || SelectedSource.Process?.Count > 0
|| Utils.IsNotEmpty(SelectedSource.Port); || Utils.IsNotEmpty(SelectedSource.Port)
|| Utils.IsNotEmpty(SelectedSource.Network);
if (!hasRule) if (!hasRule)
{ {
NoticeHandler.Instance.Enqueue(string.Format(ResUI.RoutingRuleDetailRequiredTips, "Port/Protocol/Domain/IP/Process")); NoticeHandler.Instance.Enqueue(string.Format(ResUI.RoutingRuleDetailRequiredTips, "Network/Port/Protocol/Domain/IP/Process"));
return; return;
} }
//NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); //NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null); await _updateView?.Invoke(EViewAction.CloseWindow, null);
} }
} }
} }

View File

@@ -177,12 +177,12 @@ namespace ServiceLib.ViewModels
} }
var lst = new List<RulesItem>(); var lst = new List<RulesItem>();
foreach (var it in SelectedSources ?? [SelectedSource]) var sources = SelectedSources ?? [SelectedSource];
foreach (var it in _rules)
{ {
var item = _rules.FirstOrDefault(t => t.Id == it?.Id); if (sources.Any(t => t.Id == it?.Id))
if (item != null)
{ {
var item2 = JsonUtils.DeepCopy(item); //JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item)); var item2 = JsonUtils.DeepCopy(it);
item2.Id = null; item2.Id = null;
lst.Add(item2 ?? new()); lst.Add(item2 ?? new());
} }

View File

@@ -7,9 +7,6 @@ namespace ServiceLib.ViewModels
{ {
public class RoutingSettingViewModel : MyReactiveObject public class RoutingSettingViewModel : MyReactiveObject
{ {
private RoutingItem _lockedItem;
private List<RulesItem> _lockedRules;
#region Reactive #region Reactive
private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>(); private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>();
@@ -20,12 +17,6 @@ namespace ServiceLib.ViewModels
public IList<RoutingItemModel> SelectedSources { get; set; } public IList<RoutingItemModel> SelectedSources { get; set; }
[Reactive]
public bool enableRoutingAdvanced { get; set; }
[Reactive]
public bool enableRoutingBasic { get; set; }
[Reactive] [Reactive]
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
@@ -35,25 +26,6 @@ namespace ServiceLib.ViewModels
[Reactive] [Reactive]
public string domainStrategy4Singbox { get; set; } public string domainStrategy4Singbox { get; set; }
[Reactive]
public string ProxyDomain { get; set; }
[Reactive]
public string ProxyIP { get; set; }
[Reactive]
public string DirectDomain { get; set; }
[Reactive]
public string DirectIP { get; set; }
[Reactive]
public string BlockDomain { get; set; }
[Reactive]
public string BlockIP { get; set; }
public ReactiveCommand<Unit, Unit> RoutingBasicImportRulesCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedAddCmd { get; } public ReactiveCommand<Unit, Unit> RoutingAdvancedAddCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedRemoveCmd { get; } public ReactiveCommand<Unit, Unit> RoutingAdvancedRemoveCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; } public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; }
@@ -73,15 +45,6 @@ namespace ServiceLib.ViewModels
x => x.SelectedSource, x => x.SelectedSource,
selectedSource => selectedSource != null && !selectedSource.Remarks.IsNullOrEmpty()); selectedSource => selectedSource != null && !selectedSource.Remarks.IsNullOrEmpty());
this.WhenAnyValue(
x => x.enableRoutingAdvanced)
.Subscribe(c => enableRoutingBasic = !enableRoutingAdvanced);
RoutingBasicImportRulesCmd = ReactiveCommand.CreateFromTask(async () =>
{
await RoutingBasicImportRules();
});
RoutingAdvancedAddCmd = ReactiveCommand.CreateFromTask(async () => RoutingAdvancedAddCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
await RoutingAdvancedEditAsync(true); await RoutingAdvancedEditAsync(true);
@@ -111,67 +74,14 @@ namespace ServiceLib.ViewModels
{ {
SelectedSource = new(); SelectedSource = new();
enableRoutingAdvanced = true;//TODO _config.RoutingBasicItem.EnableRoutingAdvanced;
domainStrategy = _config.RoutingBasicItem.DomainStrategy; domainStrategy = _config.RoutingBasicItem.DomainStrategy;
domainMatcher = _config.RoutingBasicItem.DomainMatcher; domainMatcher = _config.RoutingBasicItem.DomainMatcher;
domainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox; domainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox;
await ConfigHandler.InitBuiltinRouting(_config); await ConfigHandler.InitBuiltinRouting(_config);
await RefreshRoutingItems(); await RefreshRoutingItems();
await BindingLockedData();
} }
#region locked
private async Task BindingLockedData()
{
_lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (_lockedItem == null)
{
_lockedItem = new RoutingItem()
{
Remarks = "locked",
Url = string.Empty,
Locked = true,
};
await ConfigHandler.AddBatchRoutingRules(_lockedItem, Utils.GetEmbedText(Global.CustomRoutingFileName + "locked"));
}
if (_lockedItem != null)
{
_lockedRules = JsonUtils.Deserialize<List<RulesItem>>(_lockedItem.RuleSet);
ProxyDomain = Utils.List2String(_lockedRules[0].Domain, true);
ProxyIP = Utils.List2String(_lockedRules[0].Ip, true);
DirectDomain = Utils.List2String(_lockedRules[1].Domain, true);
DirectIP = Utils.List2String(_lockedRules[1].Ip, true);
BlockDomain = Utils.List2String(_lockedRules[2].Domain, true);
BlockIP = Utils.List2String(_lockedRules[2].Ip, true);
}
}
private async Task EndBindingLockedData()
{
if (_lockedItem != null)
{
_lockedRules[0].Domain = Utils.String2List(Utils.Convert2Comma(ProxyDomain.TrimEx()));
_lockedRules[0].Ip = Utils.String2List(Utils.Convert2Comma(ProxyIP.TrimEx()));
_lockedRules[1].Domain = Utils.String2List(Utils.Convert2Comma(DirectDomain.TrimEx()));
_lockedRules[1].Ip = Utils.String2List(Utils.Convert2Comma(DirectIP.TrimEx()));
_lockedRules[2].Domain = Utils.String2List(Utils.Convert2Comma(BlockDomain.TrimEx()));
_lockedRules[2].Ip = Utils.String2List(Utils.Convert2Comma(BlockIP.TrimEx()));
_lockedItem.RuleSet = JsonUtils.Serialize(_lockedRules, false);
await ConfigHandler.SaveRoutingItem(_config, _lockedItem);
}
}
#endregion locked
#region Refresh Save #region Refresh Save
public async Task RefreshRoutingItems() public async Task RefreshRoutingItems()
@@ -205,12 +115,9 @@ namespace ServiceLib.ViewModels
private async Task SaveRoutingAsync() private async Task SaveRoutingAsync()
{ {
_config.RoutingBasicItem.DomainStrategy = domainStrategy; _config.RoutingBasicItem.DomainStrategy = domainStrategy;
_config.RoutingBasicItem.EnableRoutingAdvanced = enableRoutingAdvanced;
_config.RoutingBasicItem.DomainMatcher = domainMatcher; _config.RoutingBasicItem.DomainMatcher = domainMatcher;
_config.RoutingBasicItem.DomainStrategy4Singbox = domainStrategy4Singbox; _config.RoutingBasicItem.DomainStrategy4Singbox = domainStrategy4Singbox;
await EndBindingLockedData();
if (await ConfigHandler.SaveConfig(_config) == 0) if (await ConfigHandler.SaveConfig(_config) == 0)
{ {
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
@@ -224,18 +131,6 @@ namespace ServiceLib.ViewModels
#endregion Refresh Save #endregion Refresh Save
private async Task RoutingBasicImportRules()
{
//Extra to bypass the mainland
ProxyDomain = "geosite:google";
DirectDomain = "geosite:cn";
DirectIP = "geoip:private,geoip:cn";
BlockDomain = "geosite:category-ads-all";
//NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
}
public async Task RoutingAdvancedEditAsync(bool blNew) public async Task RoutingAdvancedEditAsync(bool blNew)
{ {
RoutingItem item; RoutingItem item;

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