Compare commits

..

137 Commits
7.0.5 ... 7.3.0

Author SHA1 Message Date
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
151 changed files with 3822 additions and 2493 deletions

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

@@ -0,0 +1,32 @@
name: release macos
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
strategy:
matrix:
configuration: [Release]
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: cd v2rayN &&
./build-osx.sh
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: v2rayN-osx
path: |
./v2rayN/v2rayN-osx.zip

View File

@@ -28,7 +28,7 @@ jobs:
- name: Build
run: cd v2rayN &&
.\build.ps1
./build.ps1
# - name: Package
# shell: pwsh
@@ -40,7 +40,7 @@ jobs:
with:
name: v2rayN
path: |
.\v2rayN\v2rayN.zip
./v2rayN/v2rayN.zip
# - name: Release
# uses: softprops/action-gh-release@v1

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
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 and Linux, 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)
@@ -9,13 +9,19 @@ A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core)
## How to use
- If you are new to this, please download v2rayN-With-Core.zip from [releases](https://github.com/2dust/v2rayN/releases)
- Otherwise please download v2rayN.zip (you will also need to download cores in the bin directory)
- Run v2rayN.exe
Check [Release files introduction](https://github.com/2dust/v2rayN/wiki/Release-files-introduction) and select the version you need to download
### Windows
- Run `v2rayN.exe`
### Linux
- `chmod +x v2rayN` Run `./v2rayN`
```
Debian 9+
Ubuntu 16.04+
Fedora 30+
```
## Requirements
- (6.35 and above)[Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- (6.33 and below)[Microsoft .NET 6.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)

View File

@@ -8,5 +8,20 @@
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
<FileVersion>1.3.0</FileVersion>
</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>

View File

@@ -10,7 +10,7 @@
{
if (args.Length == 0)
{
Console.WriteLine("Please run it from the main application.(请从主应用运行)");
Console.WriteLine(Resx.Resource.Guidelines);
Thread.Sleep(5000);
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>
<!--
Microsoft ResX Schema
@@ -117,8 +117,40 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="pac" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\pac.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value>
<data name="Restartv2rayN" xml:space="preserve">
<value>正在重启,请等待...</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>
</root>

View File

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

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.Text;
@@ -98,7 +98,7 @@ namespace ServiceLib.Common
totalRead += read;
if (read == 0) break;
await file.WriteAsync(buffer, 0, read, token);
await file.WriteAsync(buffer.AsMemory(0, read), token);
if (canReportProgress)
{

View File

@@ -31,8 +31,8 @@
var parts = this.version.Split('.');
if (parts.Length == 2)
{
this.major = int.Parse(parts[0]);
this.minor = int.Parse(parts[1]);
this.major = int.Parse(parts.First());
this.minor = int.Parse(parts.Last());
this.patch = 0;
}
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)
{
if (s.IsNullOrEmpty()) return false;
return chars.Contains(s[0]);
return chars.Contains(s.First());
}
private static bool IsWhiteSpace(this string value)
@@ -61,7 +61,7 @@ namespace ServiceLib.Common
return string.Empty;
}
return char.ToUpper(value[0]) + value[1..];
return char.ToUpper(value.First()) + value[1..];
}
public static string AppendQuotes(this string value)

View File

@@ -1,4 +1,4 @@
using CliWrap;
using CliWrap;
using CliWrap.Buffered;
using System.Collections.Specialized;
using System.Diagnostics;
@@ -185,7 +185,7 @@ namespace ServiceLib.Common
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);
@@ -313,8 +313,8 @@ namespace ServiceLib.Common
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)
{
@@ -622,8 +622,8 @@ namespace ServiceLib.Common
{
if (host.StartsWith("#")) continue;
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (hostItem.Length < 2) continue;
systemHosts.Add(hostItem[1], hostItem[0]);
if (hostItem.Length != 2) continue;
systemHosts.Add(hostItem.Last(), hostItem.First());
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,6 +20,7 @@
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
public const string IPAPIUrl = "https://api.ip.sb/geoip";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json";
@@ -46,7 +47,8 @@
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 DefaultNetwork = "tcp";
public const string TcpHeaderHttp = "http";
@@ -105,9 +107,9 @@
public static readonly List<string> SpeedTestUrls = new() {
@"https://speed.cloudflare.com/__down?bytes=100000000",
@"https://speed.cloudflare.com/__down?bytes=50000000",
@"https://speed.cloudflare.com/__down?bytes=10000000",
@"http://cachefly.cachefly.net/50mb.test",
@"http://cachefly.cachefly.net/10mb.test"
@"https://cachefly.cachefly.net/50mb.test",
};
public static readonly List<string> SpeedPingTestUrls = new() {
@@ -175,19 +177,18 @@
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
public static readonly List<string> SsSecuritiesInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
public static readonly List<string> 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> CoreTypes = new() { "v2fly", "Xray", "sing_box" };
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
public static readonly List<string> CoreTypes = new() { "Xray", "sing_box" };
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
public static readonly List<string> XhttpMode = new() { "auto", "packet-up", "stream-up", "stream-one" };
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
@@ -197,7 +198,7 @@
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" };
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
public static readonly List<string> InboundTags = new() { "socks", "socks2" };
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
@@ -207,9 +208,9 @@
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" };
public static readonly List<string> notAllowTestType = new List<string> { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" };
public static readonly List<string> allowSelectType = new() { "selector", "urltest", "loadbalance", "fallback" };
public static readonly List<string> notAllowTestType = new() { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
public static readonly List<string> proxyVehicleType = new() { "file", "http" };
#endregion const
}

View File

@@ -27,7 +27,7 @@
get
{
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
return _statePort2.Value;
return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
}
}
@@ -46,11 +46,13 @@
public bool InitApp()
{
_config = ConfigHandler.LoadConfig();
if (_config == null)
Logging.Setup();
var config = ConfigHandler.LoadConfig();
if (config == null)
{
return false;
}
_config = config;
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
//Under Win10
@@ -70,15 +72,21 @@
public bool InitComponents()
{
Logging.Setup();
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
Logging.ClearLogs();
return true;
}
public bool Reset()
{
_statePort = null;
_statePort2 = null;
return true;
}
#endregion Init
#region Config
@@ -211,12 +219,12 @@
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)
{
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()
@@ -247,7 +255,7 @@
case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox;
}
return Global.SsSecuritiesInSagerNet;
return Global.SsSecuritiesInSingbox;
}
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
@@ -257,16 +265,8 @@
return (ECoreType)profileItem.CoreType;
}
if (_config.CoreTypeItem == null)
{
return ECoreType.Xray;
}
var item = _config.CoreTypeItem.FirstOrDefault(it => it.ConfigType == eConfigType);
if (item == null)
{
return ECoreType.Xray;
}
return item.CoreType;
var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType);
return item?.CoreType ?? ECoreType.Xray;
}
#endregion Core Type

View File

@@ -25,6 +25,10 @@ namespace ServiceLib.Handler
await SetTaskLinux();
}
}
else if (Utils.IsOSX())
{
//TODO
}
return true;
}
@@ -75,7 +79,7 @@ namespace ServiceLib.Handler
{
return;
}
var logonUser = WindowsIdentity.GetCurrent().Name;
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
@@ -113,7 +117,14 @@ namespace ServiceLib.Handler
private static async Task ClearTaskLinux()
{
File.Delete(GetHomePathLinux());
try
{
File.Delete(GetHomePathLinux());
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
private static async Task SetTaskLinux()
@@ -127,8 +138,6 @@ namespace ServiceLib.Handler
Logging.SaveLog(linuxConfig);
var homePath = GetHomePathLinux();
Directory.CreateDirectory(Path.GetDirectoryName(homePath));
await File.WriteAllTextAsync(homePath, linuxConfig);
}
}
@@ -140,7 +149,9 @@ namespace ServiceLib.Handler
private static string GetHomePathLinux()
{
return Path.Combine(Utils.GetHomePath(), ".config", "autostart", $"{Global.AppName}.desktop");
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;
namespace ServiceLib.Handler
@@ -62,17 +62,15 @@ namespace ServiceLib.Handler
{
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))
{
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies[0];//"IPIfNonMatch";
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();//"IPIfNonMatch";
}
config.KcpItem ??= new KcpItem
@@ -113,7 +111,7 @@ namespace ServiceLib.Handler
{
if (Thread.CurrentThread.CurrentCulture.Name.Equals("zh-cn", StringComparison.CurrentCultureIgnoreCase))
{
config.UiItem.CurrentLanguage = Global.Languages[0];
config.UiItem.CurrentLanguage = Global.Languages.First();
}
else
{
@@ -134,7 +132,7 @@ namespace ServiceLib.Handler
}
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedTestUrl))
{
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls[0];
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls.First();
}
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedPingTestUrl))
{
@@ -150,7 +148,7 @@ namespace ServiceLib.Handler
config.Mux4SboxItem ??= new()
{
Protocol = Global.SingboxMuxs[0],
Protocol = Global.SingboxMuxs.First(),
MaxConnections = 8
};
@@ -162,6 +160,7 @@ namespace ServiceLib.Handler
config.ClashUIItem ??= new();
config.SystemProxyItem ??= new();
config.WebDavItem ??= new();
config.CheckUpdateItem ??= new();
return config;
}
@@ -239,6 +238,7 @@ namespace ServiceLib.Handler
item.PublicKey = profileItem.PublicKey;
item.ShortId = profileItem.ShortId;
item.SpiderX = profileItem.SpiderX;
item.Extra = profileItem.Extra;
}
var ret = item.ConfigType switch
@@ -383,7 +383,7 @@ namespace ServiceLib.Handler
}
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)
@@ -429,7 +429,7 @@ namespace ServiceLib.Handler
{
return 0;
}
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].IndexId) - 1;
sort = ProfileExHandler.Instance.GetSort(lstProfile.First().IndexId) - 1;
break;
}
@@ -465,7 +465,7 @@ namespace ServiceLib.Handler
break;
}
case EMove.Position:
sort = pos * 10 + 1;
sort = (pos * 10) + 1;
break;
}
@@ -957,7 +957,6 @@ namespace ServiceLib.Handler
&& o.Address == n.Address
&& o.Port == n.Port
&& o.Id == n.Id
&& o.AlterId == n.AlterId
&& o.Security == n.Security
&& o.Network == n.Network
&& o.HeaderType == n.HeaderType
@@ -966,6 +965,10 @@ namespace ServiceLib.Handler
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& o.Flow == n.Flow
&& 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);
}
@@ -1023,6 +1026,35 @@ namespace ServiceLib.Handler
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
#region Batch add servers
@@ -1197,7 +1229,7 @@ namespace ServiceLib.Handler
{
await RemoveServerViaSubid(config, subid, isSub);
}
profileItem.Subid = subid;
profileItem.IsSub = isSub;
profileItem.PreSocksPort = preSocksPort;
@@ -1293,6 +1325,20 @@ namespace ServiceLib.Handler
}
}
//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;
}
@@ -1358,6 +1404,7 @@ namespace ServiceLib.Handler
item.PrevProfile = subItem.PrevProfile;
item.NextProfile = subItem.NextProfile;
item.PreSocksPort = subItem.PreSocksPort;
item.Memo = subItem.Memo;
}
if (Utils.IsNullOrEmpty(item.Id))
@@ -1594,7 +1641,7 @@ namespace ServiceLib.Handler
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
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);
return item2;
}
@@ -1668,6 +1715,15 @@ namespace ServiceLib.Handler
{
var ver = "V3-";
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)
{
return 0;
@@ -1708,11 +1764,6 @@ namespace ServiceLib.Handler
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)
{
await SQLiteHelper.Instance.DeleteAsync(routingItem);

View File

@@ -13,6 +13,7 @@ namespace ServiceLib.Handler
private Config _config;
private Process? _process;
private Process? _processPre;
private int _linuxSudoPid = -1;
private 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("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
if (Utils.IsLinux())
if (Utils.IsLinux() || Utils.IsOSX())
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo)
@@ -59,90 +60,56 @@ namespace ServiceLib.Handler
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
ShowMsg(false, result.Msg);
if (result.Success != true)
{
ShowMsg(true, result.Msg);
return;
}
else
{
ShowMsg(true, $"{node.GetSummary()}");
await CoreStop();
await CoreStart(node);
//In tun mode, do a delay check and restart the core
//if (_config.tunModeItem.enableTun)
//{
// Observable.Range(1, 1)
// .Delay(TimeSpan.FromSeconds(15))
// .Subscribe(x =>
// {
// {
// if (_process == null || _process.HasExited)
// {
// CoreStart(node);
// ShowMsg(false, "Tun mode restart the core once");
// Logging.SaveLog("Tun mode restart the core once");
// }
// }
// });
//}
}
ShowMsg(true, $"{node.GetSummary()}");
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop();
await Task.Delay(100);
await CoreStart(node);
await CoreStartPreService(node);
}
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 configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
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()
{
try
{
bool hasProc = false;
if (_process != null)
{
await KillProcess(_process);
_process.Dispose();
_process = null;
hasProc = true;
_process = await KillProcess(_process);
}
if (_processPre != null)
{
await KillProcess(_processPre);
_processPre.Dispose();
_processPre = null;
hasProc = true;
_processPre = await KillProcess(_processPre);
}
if (!hasProc)
if (_linuxSudoPid > 0)
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
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);
}
}
await KillProcessAsLinuxSudo();
}
_linuxSudoPid = -1;
}
catch (Exception ex)
{
@@ -154,8 +121,7 @@ namespace ServiceLib.Handler
{
try
{
var _p = Process.GetProcessById(pid);
await KillProcess(_p);
await KillProcess(Process.GetProcessById(pid));
}
catch (Exception ex)
{
@@ -167,7 +133,7 @@ namespace ServiceLib.Handler
private string CoreFindExe(CoreInfo coreInfo)
{
string fileName = string.Empty;
var fileName = string.Empty;
foreach (var name in coreInfo.CoreExes)
{
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
@@ -179,7 +145,7 @@ namespace ServiceLib.Handler
}
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);
ShowMsg(false, msg);
}
@@ -188,70 +154,38 @@ namespace ServiceLib.Handler
private async Task CoreStart(ProfileItem node)
{
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
//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 coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
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)
{
return;
}
_process = proc;
}
//start a pre service
private async Task CoreStartPreService(ProfileItem node)
{
if (_process != null && !_process.HasExited)
{
ProfileItem? itemSocks = null;
var preCoreType = ECoreType.sing_box;
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;
}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
if (itemSocks != null)
{
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2);
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
var fileName = Utils.GetConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
if (result.Success)
{
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = await RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
if (proc2 is not null)
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
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)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try
{
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)
{
return -1;
@@ -276,8 +207,7 @@ namespace ServiceLib.Handler
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
string msg = ex.Message;
ShowMsg(false, msg);
ShowMsg(false, ex.Message);
return -1;
}
}
@@ -287,19 +217,29 @@ namespace ServiceLib.Handler
_updateFunc?.Invoke(notify, msg);
}
private bool IsNeedSudo(ECoreType eCoreType)
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& (Utils.IsLinux() || Utils.IsOSX())
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
#endregion Private
#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
{
string fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
Process proc = new()
{
StartInfo = new()
@@ -315,33 +255,45 @@ namespace ServiceLib.Handler
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
}
};
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
}
var startUpErrorMessage = new StringBuilder();
var startUpSuccessful = false;
if (displayLog)
{
proc.OutputDataReceived += (sender, e) =>
{
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
}
if (Utils.IsNullOrEmpty(e.Data)) return;
ShowMsg(false, e.Data + Environment.NewLine);
};
proc.ErrorDataReceived += (sender, e) =>
{
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
if (Utils.IsNullOrEmpty(e.Data)) return;
ShowMsg(false, e.Data + Environment.NewLine);
if (!startUpSuccessful)
{
startUpErrorMessage.Append(msg);
}
if (!startUpSuccessful)
{
startUpErrorMessage.Append(e.Data + Environment.NewLine);
}
};
}
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)
{
proc.BeginOutputReadLine();
@@ -364,34 +316,109 @@ namespace ServiceLib.Handler
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
string msg = ex.Message;
ShowMsg(true, msg);
ShowMsg(true, ex.Message);
return null;
}
}
private async Task KillProcess(Process? proc)
private async Task<Process?> KillProcess(Process? proc)
{
if (proc is null)
{
return;
}
try
{
proc.Kill();
proc.WaitForExit(100);
if (!proc.HasExited)
{
proc.Kill();
proc.WaitForExit(100);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return null;
}
try { proc?.Kill(true); } catch { }
try { proc?.Close(); } catch { }
try { proc?.Dispose(); } catch { }
await Task.Delay(100);
return null;
}
#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
{
@@ -44,6 +42,8 @@ namespace ServiceLib.Handler
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.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
@@ -74,13 +74,15 @@ namespace ServiceLib.Handler
{
CoreType = ECoreType.Xray,
CoreExes = new List<string> { "xray", "wxray" },
Arguments = "run {0}",
Arguments = "run -c {0}",
Url = Global.XrayCoreUrl,
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.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",
VersionArg = "-version",
RedirectInfo = true,
@@ -89,7 +91,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.mihomo,
CoreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
CoreExes = new List<string> { "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash" },
Arguments = "-f config.json" + PortableMode(),
Url = Global.MihomoCoreUrl,
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",
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{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",
VersionArg = "-v",
RedirectInfo = true,
@@ -105,7 +109,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.hysteria,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria" },
Arguments = "",
Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -134,7 +138,7 @@ namespace ServiceLib.Handler
{
CoreType = ECoreType.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,
RedirectInfo = true,
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",
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.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",
VersionArg = "version",
});
@@ -157,7 +163,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo
{
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 = "",
Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -167,7 +173,7 @@ namespace ServiceLib.Handler
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.httpupgrade):
case nameof(ETransport.splithttp):
if (Utils.IsNotEmpty(item.RequestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
@@ -94,6 +93,25 @@ namespace ServiceLib.Handler.Fmt
}
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.h2):
dicQuery["type"] = nameof(ETransport.http);
@@ -156,11 +174,17 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.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.h2):
item.Network = nameof(ETransport.h2);

View File

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

View File

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

View File

@@ -21,8 +21,8 @@
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2)
{
item.Id = userInfoParts[0];
item.Security = userInfoParts[1];
item.Id = userInfoParts.First();
item.Security = userInfoParts.Last();
}
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 List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc;
private StatisticsV2rayService? _statisticsV2Ray;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox;
public List<ServerStatItem> ServerStat => _lstServerStat;
@@ -25,7 +26,7 @@
await InitData();
_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler);
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
}
@@ -33,7 +34,7 @@
{
try
{
_statisticsV2Ray?.Close();
_statisticsXray?.Close();
_statisticsSingbox?.Close();
}
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()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");

View File

@@ -2,12 +2,80 @@
{
public class ProxySettingOSX
{
/*
* 仅测试了MacOS 13.7.1 x86 版本,其他版本有待确认
*/
/// <summary>
/// 应用接口类型
/// </summary>
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge"];
/// <summary>
/// 代理类型,对应 http,https,socks
/// </summary>
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
public static async Task SetProxy(string host, int port)
{
var lstCmd = GetSetCmds(host, port);
await ExecCmd(lstCmd);
}
public static async Task UnsetProxy()
{
var lstCmd = GetUnsetCmds();
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(string host, int port)
{
List<CmdItem> lstCmd = [];
foreach (var interf in LstInterface)
{
foreach (var type in LstTypes)
{
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = [$"-{type}", interf, host, (type.Contains("socks") ? (port - 1) : port).ToString()]
});
}
}
return lstCmd;
}
private static List<CmdItem> GetUnsetCmds()
{
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;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption;
namespace ServiceLib.Handler.SysProxy
@@ -144,12 +144,12 @@ namespace ServiceLib.Handler.SysProxy
{
if (Environment.Is64BitOperatingSystem)
{
nint opt = new(optionsPtr.ToInt64() + i * optSize);
nint opt = new(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
else
{
nint opt = new(optionsPtr.ToInt32() + i * optSize);
nint opt = new(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
}
@@ -247,7 +247,7 @@ namespace ServiceLib.Handler.SysProxy
//[MarshalAs(UnmanagedType.)]
public nint options;
};
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption

View File

@@ -1,6 +1,4 @@
using PacLib;
namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy
{
public static class SysProxyHandler
{
@@ -15,8 +13,7 @@ namespace ServiceLib.Handler.SysProxy
try
{
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.http);
var portSocks = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
if (port <= 0)
{
return false;
@@ -25,7 +22,7 @@ namespace ServiceLib.Handler.SysProxy
{
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);
break;
}
@@ -33,15 +30,10 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.SetProxy(Global.Loopback, port);
break;
case ESysProxyType.ForcedChange:
{
if (Utils.IsOSX())
{
await ProxySettingOSX.SetProxy(Global.Loopback, port);
}
case ESysProxyType.ForcedChange when Utils.IsOSX():
await ProxySettingOSX.SetProxy(Global.Loopback, port);
break;
break;
}
case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy();
break;
@@ -50,23 +42,13 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.UnsetProxy();
break;
case ESysProxyType.ForcedClear:
{
if (Utils.IsOSX())
{
await ProxySettingOSX.UnsetProxy();
}
case ESysProxyType.ForcedClear when Utils.IsOSX():
await ProxySettingOSX.UnsetProxy();
break;
break;
}
case ESysProxyType.Pac when Utils.IsWindows():
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
break;
}
await SetWindowsProxyPac(port);
break;
}
if (type != ESysProxyType.Pac && Utils.IsWindows())
@@ -81,12 +63,12 @@ namespace ServiceLib.Handler.SysProxy
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.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
if (config.SystemProxyItem.NotProxyLocalAddress)
{
strExceptions = $"<local>;{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
strExceptions = $"<local>;{strExceptions}";
}
strProxy = string.Empty;
@@ -99,8 +81,16 @@ namespace ServiceLib.Handler.SysProxy
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
.Replace("{ip}", Global.Loopback)
.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
{
public class CheckUpdateItem
public class CheckUpdateModel
{
public bool? IsSelected { get; set; }
public string? CoreType { get; set; }

View File

@@ -15,15 +15,15 @@
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
@@ -46,6 +46,7 @@
public ClashUIItem ClashUIItem { get; set; }
public SystemProxyItem SystemProxyItem { get; set; }
public WebDavItem WebDavItem { get; set; }
public CheckUpdateItem CheckUpdateItem { get; set; }
public List<InItem> Inbound { get; set; }
public List<KeyEventItem> GlobalHotkeys { get; set; }
public List<CoreTypeItem> CoreTypeItem { get; set; }

View File

@@ -81,8 +81,6 @@
public int AutoUpdateInterval { get; set; }
public bool CheckPreReleaseUpdate { get; set; } = false;
public bool EnableSecurityProtocolTls13 { get; set; }
public int TrayMenuServersLimit { get; set; } = 20;
@@ -118,6 +116,7 @@
public bool EnableDragDropSort { get; set; }
public bool DoubleClick2Activate { get; set; }
public bool AutoHideStartup { get; set; }
public bool Hide2TrayWhenClose { get; set; }
public List<ColumnItem> MainColumnItem { get; set; }
public bool ShowInTaskbar { get; set; }
}
@@ -163,6 +162,7 @@
public int Mtu { get; set; }
public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPwd { get; set; }
}
[Serializable]
@@ -171,6 +171,7 @@
public int SpeedTestTimeout { get; set; }
public string SpeedTestUrl { get; set; }
public string SpeedPingTestUrl { get; set; }
public int SpeedTestPageSize { get; set; }
}
[Serializable]
@@ -180,7 +181,6 @@
public string DomainStrategy4Singbox { get; set; }
public string DomainMatcher { get; set; }
public string RoutingIndexId { get; set; }
public bool EnableRoutingAdvanced { get; set; }
}
[Serializable]
@@ -223,7 +223,6 @@
public int ProxiesSorting { get; set; }
public bool ProxiesAutoRefresh { get; set; }
public int ProxiesAutoDelayTestInterval { get; set; } = 10;
public int ConnectionsSorting { get; set; }
public bool ConnectionsAutoRefresh { get; set; }
public int ConnectionsRefreshInterval { get; set; } = 2;
}
@@ -245,4 +244,11 @@
public string? Password { 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? DownloadUrlLinux64 { get; set; }
public string? DownloadUrlLinuxArm64 { get; set; }
public string? DownloadUrlOSX64 { get; set; }
public string? DownloadUrlOSXArm64 { get; set; }
public string? Match { get; set; }
public string? VersionArg { 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()
{
string summary = string.Format("[{0}] ", (ConfigType).ToString());
string[] arrAddr = Address.Split('.');
string addr;
if (arrAddr.Length > 2)
var summary = $"[{(ConfigType).ToString()}] ";
var arrAddr = Address.Split('.');
var addr = arrAddr.Length switch
{
addr = $"{arrAddr.First()}***{arrAddr.Last()}";
}
else if (arrAddr.Length > 1)
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
> 1 => $"***{arrAddr.Last()}",
_ => Address
};
summary += ConfigType switch
{
addr = $"***{arrAddr.Last()}";
}
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;
}
EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}",
_ => $"{Remarks}({addr}:{Port})"
};
return summary;
}
public List<string>? GetAlpn()
{
if (Utils.IsNullOrEmpty(Alpn))
{
return null;
}
else
{
return Utils.String2List(Alpn);
}
return Utils.IsNullOrEmpty(Alpn) ? null : Utils.String2List(Alpn);
}
public string GetNetwork()
@@ -110,5 +91,6 @@ namespace ServiceLib.Models
public string PublicKey { get; set; }
public string ShortId { 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 string? domain_strategy { get; set; }
public string interface_name { get; set; }
public string inet4_address { get; set; }
public string? inet6_address { get; set; }
public List<string>? address { get; set; }
public int? mtu { get; set; }
public bool? auto_route { get; set; }
public bool? strict_route { get; set; }

View File

@@ -33,5 +33,7 @@ namespace ServiceLib.Models
public string? NextProfile { 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
{
/// <summary>
/// v2ray配置文件实体类 例子SampleConfig.txt
/// </summary>
public class V2rayConfig
{
/// <summary>
/// Properties that do not belong to Ray
/// </summary>
public string? remarks { get; set; }
/// <summary>
/// 日志配置
/// </summary>
public Log4Ray log { get; set; }
/// <summary>
/// 传入连接配置
/// </summary>
public List<Inbounds4Ray> inbounds { get; set; }
/// <summary>
/// 传出连接配置
/// </summary>
public List<Outbounds4Ray> outbounds { get; set; }
/// <summary>
/// 统计需要, 空对象
/// </summary>
public Stats4Ray stats { get; set; }
public Stats4Ray? stats { get; set; }
/// </summary>
public API4Ray api { get; set; }
public Metrics4Ray? metrics { get; set; }
/// </summary>
public Policy4Ray policy { get; set; }
public Policy4Ray? policy { get; set; }
/// <summary>
/// DNS 配置
/// </summary>
public object dns { get; set; }
/// <summary>
/// 路由配置
/// </summary>
public Routing4Ray routing { get; set; }
}
public class Stats4Ray
{ };
{ }
public class API4Ray
public class Metrics4Ray
{
public string tag { get; set; }
public List<string> services { get; set; }
}
public class Policy4Ray
@@ -71,124 +44,59 @@ namespace ServiceLib.Models
public class Log4Ray
{
/// <summary>
///
/// </summary>
public string access { get; set; }
public string? access { get; set; }
/// <summary>
///
/// </summary>
public string error { get; set; }
public string? error { get; set; }
/// <summary>
///
/// </summary>
public string loglevel { get; set; }
public string? loglevel { get; set; }
}
public class Inbounds4Ray
{
public string tag { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; }
/// <summary>
///
/// </summary>
public string listen { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Sniffing4Ray sniffing { get; set; }
/// <summary>
///
/// </summary>
public Inboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; }
}
public class Inboundsettings4Ray
{
/// <summary>
///
/// </summary>
public string auth { get; set; }
public string? auth { get; set; }
/// <summary>
///
/// </summary>
public bool udp { get; set; }
public bool? udp { get; set; }
/// <summary>
///
/// </summary>
public string ip { get; set; }
public string? ip { get; set; }
/// <summary>
/// api 使用
/// </summary>
public string address { get; set; }
public string? address { get; set; }
/// <summary>
///
/// </summary>
public List<UsersItem4Ray> clients { get; set; }
public List<UsersItem4Ray>? clients { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string decryption { get; set; }
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
{
/// <summary>
///
/// </summary>
public string id { get; set; }
public string? id { get; set; }
/// <summary>
///
/// </summary>
public int alterId { get; set; }
public int? alterId { get; set; }
/// <summary>
///
/// </summary>
public string email { get; set; }
public string? email { get; set; }
/// <summary>
///
/// </summary>
public string security { get; set; }
public string? security { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string encryption { get; set; }
public string? encryption { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string? flow { get; set; }
}
@@ -201,57 +109,27 @@ namespace ServiceLib.Models
public class Outbounds4Ray
{
/// <summary>
/// 默认值agentout
/// </summary>
public string tag { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Outboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; }
/// <summary>
///
/// </summary>
public Mux4Ray mux { get; set; }
}
public class Outboundsettings4Ray
{
/// <summary>
///
/// </summary>
public List<VnextItem4Ray>? vnext { get; set; }
/// <summary>
///
/// </summary>
public List<ServersItem4Ray> servers { get; set; }
public List<ServersItem4Ray>? servers { get; set; }
/// <summary>
///
/// </summary>
public Response4Ray response { get; set; }
public Response4Ray? response { get; set; }
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public int? userLevel { get; set; }
public FragmentItem4Ray? fragment { get; set; }
@@ -259,85 +137,40 @@ namespace ServiceLib.Models
public class VnextItem4Ray
{
/// <summary>
///
/// </summary>
public string address { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; }
/// <summary>
///
/// </summary>
public List<UsersItem4Ray> users { get; set; }
}
public class ServersItem4Ray
{
/// <summary>
///
/// </summary>
public string email { get; set; }
/// <summary>
///
/// </summary>
public string address { get; set; }
/// <summary>
///
/// </summary>
public string? method { get; set; }
/// <summary>
///
/// </summary>
public bool? ota { get; set; }
/// <summary>
///
/// </summary>
public string? password { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; }
/// <summary>
/// trojan
/// </summary>
public string flow { get; set; }
/// <summary>
///
/// </summary>
public List<SocksUsersItem4Ray> users { get; set; }
}
public class SocksUsersItem4Ray
{
/// <summary>
///
/// </summary>
public string user { get; set; }
/// <summary>
///
/// </summary>
public string pass { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; }
}
@@ -351,17 +184,11 @@ namespace ServiceLib.Models
public class Response4Ray
{
/// <summary>
///
/// </summary>
public string type { get; set; }
}
public class Dns4Ray
{
/// <summary>
///
/// </summary>
public List<string> servers { get; set; }
}
@@ -373,19 +200,10 @@ namespace ServiceLib.Models
public class Routing4Ray
{
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public string? domainMatcher { get; set; }
/// <summary>
///
/// </summary>
public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; }
@@ -426,87 +244,39 @@ namespace ServiceLib.Models
public class StreamSettings4Ray
{
/// <summary>
///
/// </summary>
public string network { get; set; }
/// <summary>
///
/// </summary>
public string security { get; set; }
/// <summary>
///
/// </summary>
public TlsSettings4Ray? tlsSettings { get; set; }
/// <summary>
/// Tcp传输额外设置
/// </summary>
public TcpSettings4Ray? tcpSettings { get; set; }
/// <summary>
/// Kcp传输额外设置
/// </summary>
public KcpSettings4Ray? kcpSettings { get; set; }
/// <summary>
/// ws传输额外设置
/// </summary>
public WsSettings4Ray? wsSettings { get; set; }
/// <summary>
///
/// </summary>
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
/// <summary>
///
/// </summary>
public SplithttpSettings4Ray? splithttpSettings { get; set; }
public XhttpSettings4Ray? xhttpSettings { get; set; }
/// <summary>
/// h2传输额外设置
/// </summary>
public HttpSettings4Ray? httpSettings { get; set; }
/// <summary>
/// QUIC
/// </summary>
public QuicSettings4Ray? quicSettings { get; set; }
/// <summary>
/// VLESS only
/// </summary>
public TlsSettings4Ray? realitySettings { get; set; }
/// <summary>
/// grpc
/// </summary>
public GrpcSettings4Ray? grpcSettings { get; set; }
/// <summary>
/// sockopt
/// </summary>
public Sockopt4Ray? sockopt { get; set; }
}
public class TlsSettings4Ray
{
/// <summary>
/// 是否允许不安全连接(用于客户端)
/// </summary>
public bool? allowInsecure { get; set; }
/// <summary>
///
/// </summary>
public string? serverName { get; set; }
/// <summary>
///
/// </summary>
public List<string>? alpn { get; set; }
public string? fingerprint { get; set; }
@@ -519,157 +289,94 @@ namespace ServiceLib.Models
public class TcpSettings4Ray
{
/// <summary>
/// 数据包头部伪装设置
/// </summary>
public Header4Ray header { get; set; }
}
public class Header4Ray
{
/// <summary>
/// 伪装
/// </summary>
public string type { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object request { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object response { get; set; }
}
public class KcpSettings4Ray
{
/// <summary>
///
/// </summary>
public int mtu { get; set; }
/// <summary>
///
/// </summary>
public int tti { get; set; }
/// <summary>
///
/// </summary>
public int uplinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public int downlinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public bool congestion { get; set; }
/// <summary>
///
/// </summary>
public int readBufferSize { get; set; }
/// <summary>
///
/// </summary>
public int writeBufferSize { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; }
/// <summary>
///
/// </summary>
public string seed { get; set; }
}
public class WsSettings4Ray
{
/// <summary>
///
/// </summary>
public string path { get; set; }
/// <summary>
///
/// </summary>
public Headers4Ray headers { get; set; }
}
public class Headers4Ray
{
/// <summary>
///
/// </summary>
public string Host { get; set; }
/// <summary>
/// 用户代理
/// </summary>
[JsonPropertyName("User-Agent")]
public string UserAgent { get; set; }
}
public class HttpupgradeSettings4Ray
{
/// <summary>
///
/// </summary>
public string? path { get; set; }
/// <summary>
///
/// </summary>
public string? host { get; set; }
}
public class SplithttpSettings4Ray
public class XhttpSettings4Ray
{
public string? path { get; set; }
public string? host { get; set; }
public int? maxUploadSize { get; set; }
public int? maxConcurrentUploads { get; set; }
public string? mode { get; set; }
public object? scMaxEachPostBytes { get; set; }
public object? scMaxConcurrentPosts { get; set; }
public object? scMinPostsIntervalMs { get; set; }
//public Xmux4Ray? xmux { get; set; }
public object? extra { get; set; }
}
//public class Xmux4Ray
//{
// public object? maxConcurrency { get; set; }
// public object? maxConnections { get; set; }
// public object? cMaxReuseTimes { get; set; }
// public object? cMaxLifetimeMs { get; set; }
//}
public class HttpSettings4Ray
{
/// <summary>
///
/// </summary>
public string? path { get; set; }
/// <summary>
///
/// </summary>
public List<string>? host { get; set; }
}
public class QuicSettings4Ray
{
/// <summary>
///
/// </summary>
public string security { get; set; }
/// <summary>
///
/// </summary>
public string key { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; }
}
@@ -686,14 +393,8 @@ namespace ServiceLib.Models
public class AccountsItem4Ray
{
/// <summary>
///
/// </summary>
public string user { get; set; }
/// <summary>
///
/// </summary>
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>
/// 查找类似 More URLs, separated by commas; Subscription conversion will be invalid 的本地化字符串。
/// </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>
/// 查找类似 Export selected server for complete configuration 的本地化字符串。
/// </summary>
@@ -1347,24 +1365,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>
/// 查找类似 RoutingRuleDetailsSetting 的本地化字符串。
/// </summary>
@@ -3085,6 +3085,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Hide to tray when closing the window 的本地化字符串。
/// </summary>
public static string TbSettingsHide2TrayWhenClose {
get {
return ResourceManager.GetString("TbSettingsHide2TrayWhenClose", resourceCulture);
}
}
/// <summary>
/// 查找类似 HTTP Port 的本地化字符串。
/// </summary>
@@ -3130,6 +3139,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>
/// 查找类似 Enable Log 的本地化字符串。
/// </summary>
@@ -3266,7 +3311,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 SOCKS Port 的本地化字符串。
/// 查找类似 Mixed Port 的本地化字符串。
/// </summary>
public static string TbSettingsSocksPort {
get {
@@ -3275,7 +3320,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6; 的本地化字符串。
/// 查找类似 Pac port = +2; Xray API port = +3; mihomo API port = +4; 的本地化字符串。
/// </summary>
public static string TbSettingsSocksPortTip {
get {
@@ -3292,6 +3337,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>
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
/// </summary>
@@ -3581,7 +3635,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 The ping of current service: {0} ms 的本地化字符串。
/// 查找类似 The delay : {0} ms, {1} 的本地化字符串。
/// </summary>
public static string TestMeOutput {
get {
@@ -3643,6 +3697,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 XHTTP Extra raw JSON, format: { XHTTPObject } 的本地化字符串。
/// </summary>
public static string TransportExtraTip {
get {
return ResourceManager.GetString("TransportExtraTip", resourceCulture);
}
}
/// <summary>
/// 查找类似 *tcp camouflage type 的本地化字符串。
/// </summary>
@@ -3680,7 +3743,16 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 *ws/httpupgrade/splithttp path 的本地化字符串。
/// 查找类似 *xhttp mode 的本地化字符串。
/// </summary>
public static string TransportHeaderTypeTip5 {
get {
return ResourceManager.GetString("TransportHeaderTypeTip5", resourceCulture);
}
}
/// <summary>
/// 查找类似 *ws/httpupgrade/xhttp path 的本地化字符串。
/// </summary>
public static string TransportPathTip1 {
get {
@@ -3734,7 +3806,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 *ws/httpupgrade/splithttp host 的本地化字符串。
/// 查找类似 *ws/httpupgrade/xhttp host 的本地化字符串。
/// </summary>
public static string TransportRequestHostTip2 {
get {

View File

@@ -302,7 +302,7 @@
<value>اسکن URL وارد کردن با موفقیت</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>پینگ سرویس فعلی: {0} ms</value>
<value>پینگ سرویس فعلی: {0} ms, {1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>موفقیت عملیات</value>
@@ -752,7 +752,7 @@
<value>Turn on Sniffing</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>ساکس Port</value>
<value>Mixed Port</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>درهنگام راه ائدازی شروع شود</value>
@@ -847,12 +847,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule</value>
</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">
<value>تطبیق دامنه</value>
</data>
@@ -1033,4 +1027,364 @@
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
<data name="menuRemoteBackup" xml:space="preserve">
<value>Backup to remote (WebDAV)</value>
</data>
<data name="menuRemoteRestore" xml:space="preserve">
<value>Restore from remote (WebDAV)</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Default domain strategy for outbound</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>Multi-Server lowest latency</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>Main layout orientation(Require restart)</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>Multi-server load balancing</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound DNS address</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>Auto column width adjustment</value>
</data>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>Export Base64-encoded Share Links to Clipboard</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected server for complete configuration to clipboard</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>Backup and Restore</value>
</data>
<data name="menuLocalBackup" xml:space="preserve">
<value>Backup to local</value>
</data>
<data name="menuLocalRestore" xml:space="preserve">
<value>Restore from local</value>
</data>
<data name="menuLocalBackupAndRestore" xml:space="preserve">
<value>Local</value>
</data>
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>Remote (WebDAV)</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav Url</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>WebDav User Name</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>WebDav Password</value>
</data>
<data name="LvWebDavCheck" xml:space="preserve">
<value>WebDav Check</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>Remote folder name (optional)</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>Invalid backup file</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
<data name="TipActiveServer" xml:space="preserve">
<value>Active</value>
</data>
<data name="menuStorageUI" xml:space="preserve">
<value>Save Interface Layout</value>
</data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>Geo files source (optional)</value>
</data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>sing-box ruleset files source (optional)</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>UpgradeApp does not exist</value>
</data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>Routing rules source (optional)</value>
</data>
<data name="menuRegionalPresets" xml:space="preserve">
<value>Regional presets setting</value>
</data>
<data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>Russia</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>Users in China region can ignore this item</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve">
<value>Scan QR code in the image</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="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</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="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>Enable logging to file</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>Updates are not enabled, skip this subscription</value>
</data>
<data name="menuRebootAsAdmin" xml:space="preserve">
<value>Restart as Administrator</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval (minutes)</value>
</data>
<data name="LvConvertTarget" xml:space="preserve">
<value>Convert target type</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>Please leave blank if no conversion is required</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value>
</data>
<data name="menuDNSSetting" xml:space="preserve">
<value>DNS Settings</value>
</data>
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
<value>Please fill in DNS Structure, Click to view the document</value>
</data>
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
<value>Click to import default DNS config</value>
</data>
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
<value>sing-box domain strategy</value>
</data>
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux Protocol</value>
</data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Full process name (Tun mode)</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
<value>sing-box DNS settings</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="menuMoveToGroup" xml:space="preserve">
<value>Move to group</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Enable Server Drag Drop Sort(Require restart)</value>
</data>
<data name="TbAutoRefresh" xml:space="preserve">
<value>AutoRefresh</value>
</data>
<data name="SpeedtestingSkip" xml:space="preserve">
<value>Skip test</value>
</data>
<data name="menuEditServer" xml:space="preserve">
<value>Edit Server (Ctrl+D)</value>
</data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Double-click server make active</value>
</data>
<data name="SpeedtestingCompleted" xml:space="preserve">
<value>Test completed</value>
</data>
<data name="TbSettingsDefFingerprint" xml:space="preserve">
<value>Default TLS fingerprint</value>
</data>
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
<value>FontFamily(Require restart)</value>
</data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>Pac port = +2; Xray API port = +3; mihomo API port = +4;</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>Set this with admin privileges, get admin privileges after startup</value>
</data>
<data name="TbSettingsFontSize" xml:space="preserve">
<value>Font Size</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>SpeedTest Single Timeout Value</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest URL</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</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>Hysteria Max bandwidth (Up/Dw)</value>
</data>
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
<value>Follow System Theme</value>
</data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] server</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>Updating subscription, only determine remarks exists</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>Refresh Proxies</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>Network</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>Type</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP] server</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</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="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="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>Use System Hosts</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value>
</data>
<data name="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value>
</data>
<data name="SpeedtestingStop" xml:space="preserve">
<value>Test terminating...</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>obfs password</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</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="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</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="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>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>
</root>

View File

@@ -302,7 +302,7 @@
<value>Scan import the shared link successfully</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>The ping of current service: {0} ms</value>
<value>The delay : {0} ms, {1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>Operation success</value>
@@ -344,7 +344,7 @@
<value>Please fill in the correct custom DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value>
<value>*ws/httpupgrade/xhttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -359,7 +359,7 @@
<value>*http host Separated by commas (,)</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value>
<value>*ws/httpupgrade/xhttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host Separated by commas (,)</value>
@@ -755,7 +755,7 @@
<value>Turn on Sniffing</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>SOCKS Port</value>
<value>Mixed Port</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>Start on boot</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule(Enter)</value>
</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">
<value>Domain Matcher</value>
</data>
@@ -998,7 +992,7 @@
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
</data>
<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 = +2; Xray API port = +3; mihomo API port = +4;</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>Set this with admin privileges, get admin privileges after startup</value>
@@ -1363,4 +1357,34 @@
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</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>
</root>

View File

@@ -302,7 +302,7 @@
<value>Сканирование URL-адреса импорта успешна.</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>Задержка текущего сервера: {0} мс</value>
<value>Задержка текущего сервера: {0} мс, {1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>Операция успешна</value>
@@ -761,7 +761,7 @@
<value>Включить сниффинг</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>Порт Socks</value>
<value>Mixed Port</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>Автозапуск</value>
@@ -856,12 +856,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Установить как активное правило</value>
</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">
<value>Сопоставитель доменов</value>
</data>
@@ -1046,6 +1040,351 @@
<value>Россия</value>
</data>
<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 = +2; Xray API port = +3; mihomo API port = +4;</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>
</root>

View File

@@ -302,7 +302,7 @@
<value>扫描导入分享链接成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>当前服务的真连接延迟: {0} ms</value>
<value>当前延迟: {0} ms{1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value>
@@ -344,7 +344,7 @@
<value>请填写正确的自定义DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value>
<value>*ws/httpupgrade/xhttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -359,7 +359,7 @@
<value>*http host中间逗号(,)分隔</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value>
<value>*ws/httpupgrade/xhttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中间逗号(,)分隔</value>
@@ -755,7 +755,7 @@
<value>开启流量探测</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>本地socks监听端口</value>
<value>本地混合监听端口</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>开机启动(可能会不成功)</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>设为活动规则 (Enter)</value>
</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">
<value>域名匹配算法</value>
</data>
@@ -998,7 +992,7 @@
<value>拷贝字体TTF/TTC文件到目录guiFonts重启设置</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value>
<value>Pac端口= +2Xray API端口= +3mihomo API端口= +4</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理员权限设置此项,在启动后获得管理员权限</value>
@@ -1271,7 +1265,7 @@
<value>显示或隐藏主界面</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value>
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自定义配置的Socks端口</value>
@@ -1360,4 +1354,34 @@
<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="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>
</root>

View File

@@ -127,7 +127,7 @@
<value>設定格式不正確</value>
</data>
<data name="CustomServerTips" xml:space="preserve">
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>下載開始...</value>
@@ -157,7 +157,7 @@
<value>請填寫正確格式伺服器埠</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機聽埠</value>
<value>請填寫本機聽埠</value>
</data>
<data name="FillPassword" xml:space="preserve">
<value>請填寫密碼</value>
@@ -301,7 +301,7 @@
<value>掃描匯入分享链接成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>目前服務的真連接延遲: {0} ms</value>
<value>目前延遲: {0} ms{1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value>
@@ -343,7 +343,7 @@
<value>請填寫正確的自訂DNS</value>
</data>
<data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value>
<value>*ws/httpupgrade/xhttp path</value>
</data>
<data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value>
@@ -358,7 +358,7 @@
<value>*http host中間逗號(,)分隔</value>
</data>
<data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value>
<value>*ws/httpupgrade/xhttp host</value>
</data>
<data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中間逗號(,)分隔</value>
@@ -511,7 +511,7 @@
<value>清除所有服務統計資料</value>
</data>
<data name="menuRealPingServer" xml:space="preserve">
<value>測試伺服器真連延遲(多選) (Ctrl+R)</value>
<value>測試伺服器真連延遲(多選) (Ctrl+R)</value>
</data>
<data name="menuSortServerResult" xml:space="preserve">
<value>按測試結果排序</value>
@@ -683,7 +683,7 @@
<value>進階代理設定, 協定選擇(可選)</value>
</data>
<data name="TbSettingsAllowLAN" xml:space="preserve">
<value>允許來自區域網路的連</value>
<value>允許來自區域網路的連</value>
</data>
<data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>啟動後隱藏視窗</value>
@@ -722,7 +722,7 @@
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
</data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>本機HTTP聽埠</value>
<value>本機HTTP聽埠</value>
</data>
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core時忽略Geo檔案</value>
@@ -755,7 +755,7 @@
<value>開啟流量探測</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>本機SOCKS監聽埠</value>
<value>本機混合偵聽埠</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>開機啟動(可能會不成功)</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>設為活動規則 (Enter)</value>
</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">
<value>域名匹配演算法</value>
</data>
@@ -998,7 +992,7 @@
<value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value>
<value>Pac連接埠= +2Xray API連接埠= +3mihomo API連接埠= +4</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
@@ -1094,7 +1088,7 @@
<value>請確保別名存在並且唯一</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>啟用額外監聽端口</value>
<value>啟用額外偵聽連接埠</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>啟用IPv6</value>
@@ -1106,7 +1100,7 @@
<value>自动滚动到末尾</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>真連測試址</value>
<value>真連測試址</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>更新訂閱時只判斷別名是否存在</value>
@@ -1151,10 +1145,10 @@
<value>顯示或隱藏主介面</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂設定的Socks端口</value>
<value>自訂設定的Socks連接埠</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>備份和還原</value>
@@ -1187,7 +1181,7 @@
<value>WebDav 密碼</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav 伺服器址</value>
<value>WebDav 伺服器址</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>遠端資料夾名稱(可選)</value>
@@ -1205,25 +1199,25 @@
<value>儲存介面佈局</value>
</data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>Geo文件來源(可選)</value>
<value>Geo檔案來源(可選)</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>升工具App不存在</value>
<value>升工具App不存在</value>
</data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>sing-box ruleset文件來源(可選)</value>
<value>sing-box ruleset檔案來源(可選)</value>
</data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>路由规则集来源(可)</value>
<value>路由規則集來源(可)</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>中国区域用可忽略此</value>
<value>中國區域用可忽略此</value>
</data>
<data name="menuRegionalPresets" xml:space="preserve">
<value>区域预置设置</value>
<value>區域預置設定</value>
</data>
<data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>默认区域</value>
<value>預設區域</value>
</data>
<data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>俄羅斯</value>
@@ -1232,12 +1226,162 @@
<value>掃描圖片中的二維碼</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>址(Url)無效</value>
<value>址(Url)無效</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>請不要使用不安全的HTTP協定訂閱位址</value>
</data>
<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>
</root>

View File

@@ -1,73 +1,149 @@
[
{
"remarks": "绕过bittorrent",
"outboundTag": "direct",
"protocol": [
"bittorrent"
]
},
{
"remarks": "Google cn",
"outboundTag": "proxy",
"domain": [
"domain:googleapis.cn",
"domain:gstatic.com"
]
},
{
"remarks": "阻断udp443",
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{
"remarks": "阻断广告",
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
},
{
"remarks": "绕过局域网IP",
"outboundTag": "direct",
"ip": [
"geoip:private"
]
},
{
"remarks": "绕过局域网域名",
"outboundTag": "direct",
"domain": [
"geosite:private"
]
},
{
"remarks": "代理IP",
"outboundTag": "proxy",
"ip": [
"1.0.0.1",
"1.1.1.1",
"8.8.8.8",
"8.8.4.4",
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
]
},
{
"remarks": "代理GFW",
"outboundTag": "proxy",
"domain": [
"geosite:gfw",
"geosite:greatfire"
]
},
{
"remarks": "最终直连",
"port": "0-65535",
"outboundTag": "direct"
}
{
"remarks": "绕过bittorrent",
"outboundTag": "direct",
"protocol": [
"bittorrent"
]
},
{
"remarks": "Google cn",
"outboundTag": "proxy",
"domain": [
"domain:googleapis.cn",
"domain:gstatic.com"
]
},
{
"remarks": "阻断udp443",
"outboundTag": "block",
"port": "443",
"network": "udp"
},
{
"remarks": "阻断广告",
"outboundTag": "block",
"domain": [
"geosite:category-ads-all"
]
},
{
"remarks": "绕过局域网IP",
"outboundTag": "direct",
"ip": [
"geoip:private"
]
},
{
"remarks": "绕过局域网域名",
"outboundTag": "direct",
"domain": [
"geosite:private"
]
},
{
"remarks": "代理海外公共DNSIP",
"outboundTag": "proxy",
"ip": [
"1.1.1.1",
"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": "代理海外公共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",
"ip": [
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
]
},
{
"remarks": "代理GFW",
"outboundTag": "proxy",
"domain": [
"geosite:gfw",
"geosite:greatfire"
]
},
{
"remarks": "最终直连",
"port": "0-65535",
"outboundTag": "direct"
}
]

View File

@@ -1,4 +1,5 @@
[{
[
{
"remarks": "block",
"outboundTag": "block",
"domain": [
@@ -12,14 +13,14 @@
"geosite:cn"
]
},
{
"remarks": "direct",
"outboundTag": "direct",
"ip": [
"geoip:private",
"geoip:cn"
]
},
{
"remarks": "direct",
"outboundTag": "direct",
"ip": [
"geoip:private",
"geoip:cn"
]
},
{
"remarks": "proxy",
"port": "0-65535",

View File

@@ -34,29 +34,62 @@
"geosite:private"
]
},
{
"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",
"domain": [
"domain:alidns.com",
"domain:doh.pub",
"domain:dot.pub",
"domain:360.cn",
"domain:onedns.net"
]
},
{
"remarks": "绕过中国IP",
"outboundTag": "direct",
"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"
]
},
@@ -64,13 +97,7 @@
"remarks": "绕过中国域名",
"outboundTag": "direct",
"domain": [
"domain:dns.alidns.com",
"domain:doh.pub",
"domain:dot.pub",
"domain:doh.360.cn",
"domain:dot.360.cn",
"geosite:cn",
"geosite:geolocation-cn"
"geosite:cn"
]
},
{

View File

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

View File

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

View File

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

View File

@@ -4,17 +4,17 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>7.0.5</Version>
<Version>7.3.0</Version>
</PropertyGroup>
<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.Fody" Version="19.5.41" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="Splat.NLog" Version="15.2.22" />
<PackageReference Include="WebDav.Client" Version="2.8.0" />
<PackageReference Include="YamlDotNet" Version="16.1.3" />
<PackageReference Include="YamlDotNet" Version="16.2.1" />
<PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="CliWrap" Version="3.6.7" />
<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />
@@ -33,6 +33,7 @@
<EmbeddedResource Include="Sample\custom_routing_white" />
<EmbeddedResource Include="Sample\dns_singbox_normal" />
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
<EmbeddedResource Include="Sample\pac" />
<EmbeddedResource Include="Sample\SampleClientConfig" />
<EmbeddedResource Include="Sample\SampleHttpRequest" />
<EmbeddedResource Include="Sample\SampleHttpResponse" />
@@ -46,12 +47,6 @@
<EmbeddedResource Include="Sample\linux_autostart_config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PacLib\PacLib.csproj" />
<ProjectReference Include="..\ProtosLib\ProtosLib.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Resx\ResUI.Designer.cs">
<DependentUpon>ResUI.resx</DependentUpon>

View File

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

View File

@@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Net;
using System.Net.NetworkInformation;
@@ -26,7 +26,7 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.CheckServerSettings;
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()}";
return ret;
@@ -52,7 +52,7 @@ namespace ServiceLib.Services.CoreConfig
await GenInbounds(singboxConfig);
await GenOutbound(node, singboxConfig.outbounds[0]);
await GenOutbound(node, singboxConfig.outbounds.First());
await GenMoreOutbounds(node, singboxConfig);
@@ -90,8 +90,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
var result = Utils.GetEmbedText(Global.SingboxSampleClient);
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -119,10 +119,10 @@ namespace ServiceLib.Services.CoreConfig
await GenLog(singboxConfig);
//GenDns(new(), singboxConfig);
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
singboxConfig.inbounds.Clear();
singboxConfig.outbounds.RemoveAt(0);
int httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds)
{
@@ -174,7 +174,7 @@ namespace ServiceLib.Services.CoreConfig
{
listen = Global.Loopback,
listen_port = port,
type = EInboundProtocol.http.ToString(),
type = EInboundProtocol.mixed.ToString(),
};
inbound.tag = inbound.type + inbound.listen_port.ToString();
singboxConfig.inbounds.Add(inbound);
@@ -484,57 +484,44 @@ namespace ServiceLib.Services.CoreConfig
singboxConfig.inbounds = [];
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()
{
type = EInboundProtocol.socks.ToString(),
type = EInboundProtocol.mixed.ToString(),
tag = EInboundProtocol.socks.ToString(),
listen = Global.Loopback,
};
singboxConfig.inbounds.Add(inbound);
inbound.listen_port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
inbound.sniff = _config.Inbound[0].SniffingEnabled;
inbound.sniff_override_destination = _config.Inbound[0].RouteOnly ? false : _config.Inbound[0].SniffingEnabled;
inbound.sniff = _config.Inbound.First().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;
if (_config.RoutingBasicItem.EnableRoutingAdvanced)
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.DomainStrategy4Singbox))
{
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.DomainStrategy4Singbox))
{
inbound.domain_strategy = routing.DomainStrategy4Singbox;
}
inbound.domain_strategy = routing.DomainStrategy4Singbox;
}
//http
var inbound2 = GetInbound(inbound, EInboundProtocol.http, false);
singboxConfig.inbounds.Add(inbound2);
if (_config.Inbound[0].AllowLANConn)
if (_config.Inbound.First().AllowLANConn)
{
if (_config.Inbound[0].NewPort4LAN)
if (_config.Inbound.First().NewPort4LAN)
{
var inbound3 = GetInbound(inbound, EInboundProtocol.socks2, true);
inbound3.listen = listen;
singboxConfig.inbounds.Add(inbound3);
var inbound4 = GetInbound(inbound, EInboundProtocol.http2, false);
inbound4.listen = listen;
singboxConfig.inbounds.Add(inbound4);
//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 } };
inbound4.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 } };
}
}
else
{
inbound.listen = listen;
inbound2.listen = listen;
}
}
}
@@ -543,22 +530,23 @@ namespace ServiceLib.Services.CoreConfig
{
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))
{
_config.TunModeItem.Stack = Global.TunStacks[0];
_config.TunModeItem.Stack = Global.TunStacks.First();
}
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.strict_route = _config.TunModeItem.StrictRoute;
tunInbound.stack = _config.TunModeItem.Stack;
tunInbound.sniff = _config.Inbound[0].SniffingEnabled;
//tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
tunInbound.sniff = _config.Inbound.First().SniffingEnabled;
//tunInbound.sniff_override_destination = _config.inbound.First().routeOnly ? false : _config.inbound.First().sniffingEnabled;
if (_config.TunModeItem.EnableIPv6Address == false)
{
tunInbound.inet6_address = null;
tunInbound.address = ["172.18.0.1/30"];
}
singboxConfig.inbounds.Add(tunInbound);
@@ -576,7 +564,7 @@ namespace ServiceLib.Services.CoreConfig
var inbound = JsonUtils.DeepCopy(inItem);
inbound.tag = protocol.ToString();
inbound.listen_port = inItem.listen_port + (int)protocol;
inbound.type = bSocks ? EInboundProtocol.socks.ToString() : EInboundProtocol.http.ToString();
inbound.type = EInboundProtocol.mixed.ToString();
return inbound;
}
@@ -869,7 +857,7 @@ namespace ServiceLib.Services.CoreConfig
}
//current proxy
var outbound = singboxConfig.outbounds[0];
var outbound = singboxConfig.outbounds.First();
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
//Previous proxy
@@ -912,7 +900,7 @@ namespace ServiceLib.Services.CoreConfig
try
{
var dnsOutbound = "dns_out";
if (!_config.Inbound[0].SniffingEnabled)
if (!_config.Inbound.First().SniffingEnabled)
{
singboxConfig.route.rules.Add(new()
{
@@ -958,28 +946,13 @@ namespace ServiceLib.Services.CoreConfig
});
}
if (_config.RoutingBasicItem.EnableRoutingAdvanced)
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
{
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules ?? [])
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
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 ?? [])
if (item.Enabled)
{
await GenRoutingUserRule(item, singboxConfig.route.rules);
}
@@ -1334,20 +1307,18 @@ namespace ServiceLib.Services.CoreConfig
//load custom ruleset file
List<Ruleset4Sbox> customRulesets = [];
if (_config.RoutingBasicItem.EnableRoutingAdvanced)
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox))
{
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox))
var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox);
if (Utils.IsNotEmpty(result))
{
var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox);
if (Utils.IsNotEmpty(result))
{
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
.Where(t => t.tag != null)
.Where(t => t.type != null)
.Where(t => t.format != null)
.ToList();
}
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
.Where(t => t.tag != null)
.Where(t => t.type != null)
.Where(t => t.format != null)
.ToList();
}
}

View File

@@ -27,6 +27,12 @@ namespace ServiceLib.Services.CoreConfig
return ret;
}
if (node.GetNetwork() is nameof(ETransport.quic))
{
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret;
}
ret.Msg = ResUI.InitialConfiguration;
var result = Utils.GetEmbedText(Global.V2raySampleClient);
@@ -49,7 +55,7 @@ namespace ServiceLib.Services.CoreConfig
await GenRouting(v2rayConfig);
await GenOutbound(node, v2rayConfig.outbounds[0]);
await GenOutbound(node, v2rayConfig.outbounds.First());
await GenMoreOutbounds(node, v2rayConfig);
@@ -210,8 +216,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
var result = Utils.GetEmbedText(Global.V2raySampleClient);
var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -238,10 +244,11 @@ namespace ServiceLib.Services.CoreConfig
}
await GenLog(v2rayConfig);
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
v2rayConfig.outbounds.RemoveAt(0);
v2rayConfig.inbounds.Clear();
v2rayConfig.outbounds.Clear();
v2rayConfig.routing.rules.Clear();
int httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds)
{
@@ -264,7 +271,7 @@ namespace ServiceLib.Services.CoreConfig
//find unused port
var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++)
for (var k = httpPort; k < Global.MaxPort; k++)
{
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{
@@ -288,16 +295,6 @@ namespace ServiceLib.Services.CoreConfig
it.Port = port;
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
if (item is null)
{
@@ -320,6 +317,16 @@ namespace ServiceLib.Services.CoreConfig
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);
await GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.port.ToString();
@@ -366,8 +373,8 @@ namespace ServiceLib.Services.CoreConfig
else
{
v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel;
v2rayConfig.log.access = "";
v2rayConfig.log.error = "";
v2rayConfig.log.access = null;
v2rayConfig.log.error = null;
}
}
catch (Exception ex)
@@ -384,39 +391,27 @@ namespace ServiceLib.Services.CoreConfig
var listen = "0.0.0.0";
v2rayConfig.inbounds = [];
Inbounds4Ray? inbound = GetInbound(_config.Inbound[0], EInboundProtocol.socks, true);
var inbound = GetInbound(_config.Inbound.First(), EInboundProtocol.socks, true);
v2rayConfig.inbounds.Add(inbound);
//http
Inbounds4Ray? inbound2 = GetInbound(_config.Inbound[0], EInboundProtocol.http, false);
v2rayConfig.inbounds.Add(inbound2);
if (_config.Inbound[0].AllowLANConn)
if (_config.Inbound.First().AllowLANConn)
{
if (_config.Inbound[0].NewPort4LAN)
if (_config.Inbound.First().NewPort4LAN)
{
var inbound3 = GetInbound(_config.Inbound[0], EInboundProtocol.socks2, true);
var inbound3 = GetInbound(_config.Inbound.First(), EInboundProtocol.socks2, true);
inbound3.listen = listen;
v2rayConfig.inbounds.Add(inbound3);
var inbound4 = GetInbound(_config.Inbound[0], EInboundProtocol.http2, false);
inbound4.listen = listen;
v2rayConfig.inbounds.Add(inbound4);
//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.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.Inbound[0].User, pass = _config.Inbound[0].Pass } };
inbound4.settings.auth = "password";
inbound4.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 } };
}
}
else
{
inbound.listen = listen;
inbound2.listen = listen;
}
}
}
@@ -442,7 +437,7 @@ namespace ServiceLib.Services.CoreConfig
}
inbound.tag = protocol.ToString();
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.sniffing.enabled = inItem.SniffingEnabled;
inbound.sniffing.destOverride = inItem.DestOverride;
@@ -460,33 +455,17 @@ namespace ServiceLib.Services.CoreConfig
v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy;
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 (routing != null)
if (Utils.IsNotEmpty(routing.DomainStrategy))
{
if (Utils.IsNotEmpty(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);
}
}
v2rayConfig.routing.domainStrategy = routing.DomainStrategy;
}
}
else
{
var lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (lockedItem != null)
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules)
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(lockedItem.RuleSet);
foreach (var item in rules)
if (item.Enabled)
{
var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
await GenRoutingUserRule(item2, v2rayConfig);
@@ -596,7 +575,7 @@ namespace ServiceLib.Services.CoreConfig
}
else
{
vnextItem = outbound.settings.vnext[0];
vnextItem = outbound.settings.vnext.First();
}
vnextItem.address = node.Address;
vnextItem.port = node.Port;
@@ -609,7 +588,7 @@ namespace ServiceLib.Services.CoreConfig
}
else
{
usersItem = vnextItem.users[0];
usersItem = vnextItem.users.First();
}
//远程服务器用户ID
usersItem.id = node.Id;
@@ -639,7 +618,7 @@ namespace ServiceLib.Services.CoreConfig
}
else
{
serversItem = outbound.settings.servers[0];
serversItem = outbound.settings.servers.First();
}
serversItem.address = node.Address;
serversItem.port = node.Port;
@@ -665,7 +644,7 @@ namespace ServiceLib.Services.CoreConfig
}
else
{
serversItem = outbound.settings.servers[0];
serversItem = outbound.settings.servers.First();
}
serversItem.address = node.Address;
serversItem.port = node.Port;
@@ -700,7 +679,7 @@ namespace ServiceLib.Services.CoreConfig
}
else
{
vnextItem = outbound.settings.vnext[0];
vnextItem = outbound.settings.vnext.First();
}
vnextItem.address = node.Address;
vnextItem.port = node.Port;
@@ -713,7 +692,7 @@ namespace ServiceLib.Services.CoreConfig
}
else
{
usersItem = vnextItem.users[0];
usersItem = vnextItem.users.First();
}
usersItem.id = node.Id;
usersItem.email = Global.UserEMail;
@@ -749,7 +728,7 @@ namespace ServiceLib.Services.CoreConfig
}
else
{
serversItem = outbound.settings.servers[0];
serversItem = outbound.settings.servers.First();
}
serversItem.address = node.Address;
serversItem.port = node.Port;
@@ -920,23 +899,34 @@ namespace ServiceLib.Services.CoreConfig
streamSettings.httpupgradeSettings = httpupgradeSettings;
break;
//splithttp
case nameof(ETransport.splithttp):
SplithttpSettings4Ray splithttpSettings = new()
//xhttp
case nameof(ETransport.xhttp):
streamSettings.network = ETransport.xhttp.ToString();
XhttpSettings4Ray xhttpSettings = new()
{
maxUploadSize = 1000000,
maxConcurrentUploads = 10
scMaxEachPostBytes = "500000-1000000",
scMaxConcurrentPosts = "50-100",
scMinPostsIntervalMs = "30-50"
};
if (Utils.IsNotEmpty(node.Path))
{
splithttpSettings.path = node.Path;
xhttpSettings.path = node.Path;
}
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;
break;
//h2
@@ -1006,18 +996,17 @@ namespace ServiceLib.Services.CoreConfig
//request Host
string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
string[] arrHost = host.Split(',');
string host2 = string.Join("\",\"", arrHost);
request = request.Replace("$requestHost$", $"\"{host2}\"");
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost()));
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
string host2 = string.Join(",".AppendQuotes(), arrHost);
request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
//Path
string pathHttp = @"/";
if (Utils.IsNotEmpty(node.Path))
{
string[] arrPath = node.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);
streamSettings.tcpSettings = tcpSettings;
@@ -1120,17 +1109,14 @@ namespace ServiceLib.Services.CoreConfig
if (_config.GuiItem.EnableStatistics)
{
string tag = EInboundProtocol.api.ToString();
API4Ray apiObj = new();
Metrics4Ray apiObj = new();
Policy4Ray policyObj = new();
SystemPolicy4Ray policySystemSetting = new();
string[] services = { "StatsService" };
v2rayConfig.stats = new Stats4Ray();
apiObj.tag = tag;
apiObj.services = services.ToList();
v2rayConfig.api = apiObj;
v2rayConfig.metrics = apiObj;
policySystemSetting.statsOutboundDownlink = true;
policySystemSetting.statsOutboundUplink = true;
@@ -1169,7 +1155,7 @@ namespace ServiceLib.Services.CoreConfig
{
//fragment proxy
if (_config.CoreBasicItem.EnableFragment
&& Utils.IsNotEmpty(v2rayConfig.outbounds[0].streamSettings?.security))
&& Utils.IsNotEmpty(v2rayConfig.outbounds.First().streamSettings?.security))
{
var fragmentOutbound = new Outbounds4Ray
{
@@ -1187,7 +1173,7 @@ namespace ServiceLib.Services.CoreConfig
};
v2rayConfig.outbounds.Add(fragmentOutbound);
v2rayConfig.outbounds[0].streamSettings.sockopt = new()
v2rayConfig.outbounds.First().streamSettings.sockopt = new()
{
dialerProxy = fragmentOutbound.tag
};
@@ -1207,7 +1193,7 @@ namespace ServiceLib.Services.CoreConfig
}
//current proxy
var outbound = v2rayConfig.outbounds[0];
var outbound = v2rayConfig.outbounds.First();
var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
//Previous proxy

View File

@@ -280,7 +280,7 @@ namespace ServiceLib.Services
{
return null;
}
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.http);
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
if (await SocketCheck(Global.Loopback, httpPort) == false)
{
return null;

View File

@@ -1,4 +1,5 @@
using System.Diagnostics;
using ReactiveUI;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
@@ -7,19 +8,16 @@ namespace ServiceLib.Services
public class SpeedtestService
{
private Config? _config;
private List<ServerTestItem> _selecteds;
private ESpeedActionType _actionType;
private Action<SpeedTestResult>? _updateFunc;
private bool _exitLoop = false;
public SpeedtestService(Config config, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> updateFunc)
{
_config = config;
_actionType = actionType;
_updateFunc = updateFunc;
_selecteds = new List<ServerTestItem>();
var lstSelected = new List<ServerTestItem>();
foreach (var it in selecteds)
{
if (it.ConfigType == EConfigType.Custom)
@@ -30,7 +28,7 @@ namespace ServiceLib.Services
{
continue;
}
_selecteds.Add(new ServerTestItem()
lstSelected.Add(new ServerTestItem()
{
IndexId = it.IndexId,
Address = it.Address,
@@ -38,8 +36,9 @@ namespace ServiceLib.Services
ConfigType = it.ConfigType
});
}
//clear test result
foreach (var it in _selecteds)
foreach (var it in lstSelected)
{
switch (actionType)
{
@@ -62,38 +61,74 @@ namespace ServiceLib.Services
}
}
switch (actionType)
{
case ESpeedActionType.Tcping:
Task.Run(RunTcping);
break;
MessageBus.Current.Listen<string>(EMsgCommand.StopSpeedtest.ToString()).Subscribe(ExitLoop);
case ESpeedActionType.Realping:
Task.Run(RunRealPing);
break;
case ESpeedActionType.Speedtest:
Task.Run(RunSpeedTestAsync);
break;
case ESpeedActionType.Mixedtest:
Task.Run(RunMixedtestAsync);
break;
}
Task.Run(async () => { await RunAsync(actionType, lstSelected); });
}
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;
UpdateFunc("", ResUI.SpeedtestingStop);
}
private async Task RunTcping()
private async Task RunTcpingAsync(List<ServerTestItem> selecteds)
{
try
{
List<Task> tasks = [];
foreach (var it in _selecteds)
foreach (var it in selecteds)
{
if (it.ConfigType == EConfigType.Custom)
{
@@ -103,7 +138,7 @@ namespace ServiceLib.Services
{
try
{
int time = await GetTcpingTime(it.Address, it.Port);
var time = await GetTcpingTime(it.Address, it.Port);
var output = FormatOut(time, Global.DelayUnit);
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
{
string msg = string.Empty;
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
if (pid < 0)
{
UpdateFunc("", ResUI.FailedToRunCore);
return;
}
DownloadService downloadHandle = new DownloadService();
var downloadHandle = new DownloadService();
List<Task> tasks = new();
foreach (var it in _selecteds)
foreach (var it in selecteds)
{
if (!it.AllowTest)
{
@@ -159,11 +192,11 @@ namespace ServiceLib.Services
try
{
WebProxy webProxy = new(Global.Loopback, it.Port);
string output = await GetRealPingTime(downloadHandle, webProxy);
var output = await GetRealPingTime(downloadHandle, webProxy);
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
UpdateFunc(it.IndexId, output);
int.TryParse(output, out int delay);
int.TryParse(output, out var delay);
it.Delay = delay;
}
catch (Exception ex)
@@ -182,33 +215,28 @@ namespace ServiceLib.Services
{
if (pid > 0)
{
CoreHandler.Instance.CoreStopPid(pid);
await CoreHandler.Instance.CoreStopPid(pid);
}
await ProfileExHandler.Instance.SaveTo();
}
}
private async Task RunSpeedTestAsync()
private async Task RunSpeedTestAsync(List<ServerTestItem> selecteds)
{
int pid = -1;
//if (_actionType == ESpeedActionType.Mixedtest)
//{
// _selecteds = _selecteds.OrderBy(t => t.delay).ToList();
//}
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
var pid = -1;
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
if (pid < 0)
{
UpdateFunc("", ResUI.FailedToRunCore);
return;
}
string url = _config.SpeedTestItem.SpeedTestUrl;
var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
DownloadService downloadHandle = new();
foreach (var it in _selecteds)
foreach (var it in selecteds)
{
if (_exitLoop)
{
@@ -238,7 +266,7 @@ namespace ServiceLib.Services
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
{
decimal.TryParse(msg, out decimal dec);
decimal.TryParse(msg, out var dec);
if (dec > 0)
{
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
@@ -249,28 +277,27 @@ namespace ServiceLib.Services
if (pid > 0)
{
CoreHandler.Instance.CoreStopPid(pid);
await CoreHandler.Instance.CoreStopPid(pid);
}
UpdateFunc("", ResUI.SpeedtestingCompleted);
await ProfileExHandler.Instance.SaveTo();
}
private async Task RunSpeedTestMulti()
private async Task RunSpeedTestMulti(List<ServerTestItem> selecteds)
{
int pid = -1;
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(_selecteds);
var pid = -1;
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
if (pid < 0)
{
UpdateFunc("", ResUI.FailedToRunCore);
return;
}
string url = _config.SpeedTestItem.SpeedTestUrl;
var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
DownloadService downloadHandle = new();
foreach (var it in _selecteds)
foreach (var it in selecteds)
{
if (_exitLoop)
{
@@ -300,7 +327,7 @@ namespace ServiceLib.Services
WebProxy webProxy = new(Global.Loopback, it.Port);
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
{
decimal.TryParse(msg, out decimal dec);
decimal.TryParse(msg, out var dec);
if (dec > 0)
{
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
@@ -314,38 +341,37 @@ namespace ServiceLib.Services
if (pid > 0)
{
CoreHandler.Instance.CoreStopPid(pid);
await CoreHandler.Instance.CoreStopPid(pid);
}
UpdateFunc("", ResUI.SpeedtestingCompleted);
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 RunSpeedTestMulti();
await RunSpeedTestMulti(selecteds);
}
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;
return FormatOut(responseTime, Global.DelayUnit);
}
private async Task<int> GetTcpingTime(string url, int port)
{
int responseTime = -1;
var responseTime = -1;
try
{
if (!IPAddress.TryParse(url, out IPAddress? ipAddress))
if (!IPAddress.TryParse(url, out var ipAddress))
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(url);
ipAddress = ipHostInfo.AddressList[0];
var ipHostInfo = await Dns.GetHostEntryAsync(url);
ipAddress = ipHostInfo.AddressList.First();
}
var timer = Stopwatch.StartNew();

View File

@@ -8,9 +8,9 @@ namespace ServiceLib.Services.Statistics
private Config _config;
private bool _exitFlag;
private ClientWebSocket? webSocket;
private string url = string.Empty;
private Action<ServerSpeedItem>? _updateFunc;
private string Url => $"ws://{Global.Loopback}:{AppHandler.Instance.StatePort2}/traffic";
public StatisticsSingboxService(Config config, Action<ServerSpeedItem> updateFunc)
{
_config = config;
@@ -26,12 +26,10 @@ namespace ServiceLib.Services.Statistics
try
{
url = $"ws://{Global.Loopback}:{AppHandler.Instance.StatePort2}/traffic";
if (webSocket == null)
{
webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
await webSocket.ConnectAsync(new Uri(Url), CancellationToken.None);
}
}
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;
namespace ServiceLib.Services
@@ -6,12 +6,10 @@ namespace ServiceLib.Services
public class UpdateService
{
private Action<bool, string>? _updateFunc;
private Config _config;
private int _timeout = 30;
public async Task CheckUpdateGuiN(Config config, Action<bool, string> updateFunc, bool preRelease)
{
_config = config;
_updateFunc = updateFunc;
var url = 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)
{
_config = config;
_updateFunc = updateFunc;
var url = string.Empty;
var fileName = string.Empty;
@@ -108,7 +105,6 @@ namespace ServiceLib.Services
public async Task UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
_updateFunc?.Invoke(false, ResUI.MsgUpdateSubscriptionStart);
@@ -126,7 +122,7 @@ namespace ServiceLib.Services
var url = item.Url.TrimEx();
var userAgent = item.UserAgent.TrimEx();
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}");
continue;
@@ -232,7 +228,7 @@ namespace ServiceLib.Services
}
_updateFunc?.Invoke(false, "-------------------------------------------------------");
await ConfigHandler.DedupServerList(config, id);
//await ConfigHandler.DedupServerList(config, id);
}
_updateFunc?.Invoke(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
@@ -248,8 +244,17 @@ namespace ServiceLib.Services
public async Task RunAvailabilityCheck(Action<bool, string> updateFunc)
{
var time = await new DownloadService().RunAvailabilityCheck(null);
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time));
var downloadHandle = new DownloadService();
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
@@ -445,6 +450,15 @@ namespace ServiceLib.Services
_ => null,
};
}
else if (Utils.IsOSX())
{
return RuntimeInformation.ProcessArchitecture switch
{
Architecture.Arm64 => coreInfo?.DownloadUrlOSXArm64,
Architecture.X64 => coreInfo?.DownloadUrlOSX64,
_ => null,
};
}
return null;
}
@@ -454,7 +468,6 @@ namespace ServiceLib.Services
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
var geoUrl = string.IsNullOrEmpty(config?.ConstItem.GeoSourceUrl)
@@ -470,7 +483,6 @@ namespace ServiceLib.Services
private async Task UpdateSrsFileAll(Config config, Action<bool, string> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
var geoipFiles = new List<string>();
@@ -521,9 +533,9 @@ namespace ServiceLib.Services
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
: _config.ConstItem.SrsSourceUrl;
: config.ConstItem.SrsSourceUrl;
var fileName = $"{type}-{srsName}.srs";
var targetPath = Path.Combine(Utils.GetBinPath("srss"), fileName);

View File

@@ -12,10 +12,10 @@ namespace ServiceLib.ViewModels
{
private const string _geo = "GeoFiles";
private string _v2rayN = ECoreType.v2rayN.ToString();
private List<CheckUpdateItem> _lstUpdated = [];
private List<CheckUpdateModel> _lstUpdated = [];
private IObservableCollection<CheckUpdateItem> _checkUpdateItem = new ObservableCollectionExtended<CheckUpdateItem>();
public IObservableCollection<CheckUpdateItem> CheckUpdateItems => _checkUpdateItem;
private IObservableCollection<CheckUpdateModel> _checkUpdateModel = new ObservableCollectionExtended<CheckUpdateModel>();
public IObservableCollection<CheckUpdateModel> CheckUpdateModels => _checkUpdateModel;
public ReactiveCommand<Unit, Unit> CheckUpdateCmd { get; }
[Reactive] public bool EnableCheckPreReleaseUpdate { get; set; }
@@ -29,65 +29,56 @@ namespace ServiceLib.ViewModels
await CheckUpdate();
});
EnableCheckPreReleaseUpdate = _config.GuiItem.CheckPreReleaseUpdate;
EnableCheckPreReleaseUpdate = _config.CheckUpdateItem.CheckPreReleaseUpdate;
this.WhenAnyValue(
x => x.EnableCheckPreReleaseUpdate,
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)
{
_checkUpdateItem.Add(new CheckUpdateItem()
{
IsSelected = false,
CoreType = _v2rayN,
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(_v2rayN));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.Xray.ToString()));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.mihomo.ToString()));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.sing_box.ToString()));
}
_checkUpdateModel.Add(GetCheckUpdateModel(_geo));
}
_checkUpdateItem.Add(new CheckUpdateItem()
private CheckUpdateModel GetCheckUpdateModel(string coreType)
{
return new()
{
IsSelected = true,
CoreType = _geo,
IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType) ?? true,
CoreType = coreType,
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()
{
_lstUpdated.Clear();
_lstUpdated = _checkUpdateItem.Where(x => x.IsSelected == true)
.Select(x => new CheckUpdateItem() { CoreType = x.CoreType }).ToList();
_lstUpdated = _checkUpdateModel.Where(x => x.IsSelected == true)
.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;
UpdateView(item.CoreType, "...");
@@ -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)
{
UpdateView(item.CoreType, msg);
UpdateView(model.CoreType, msg);
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)
.ContinueWith(t =>
{
UpdatedPlusPlus(item.CoreType, "");
UpdatedPlusPlus(model.CoreType, "");
});
}
@@ -271,12 +262,12 @@ namespace ServiceLib.ViewModels
FileManager.ZipExtractToFile(fileName, toPath, _config.GuiItem.IgnoreGeoUpdateCore ? "geo" : "");
}
if (Utils.IsLinux())
if (Utils.IsLinux() || Utils.IsOSX())
{
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
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)
{
var item = new CheckUpdateItem()
var item = new CheckUpdateModel()
{
CoreType = coreType,
Remarks = msg,
@@ -299,13 +290,13 @@ namespace ServiceLib.ViewModels
_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;
var itemCopy = JsonUtils.DeepCopy(found);
itemCopy.Remarks = item.Remarks;
_checkUpdateItem.Replace(found, itemCopy);
itemCopy.Remarks = model.Remarks;
_checkUpdateModel.Replace(found, itemCopy);
}
}
}

View File

@@ -21,9 +21,6 @@ namespace ServiceLib.ViewModels
[Reactive]
public string HostFilter { get; set; }
[Reactive]
public int SortingSelected { get; set; }
[Reactive]
public bool AutoRefresh { get; set; }
@@ -31,18 +28,12 @@ namespace ServiceLib.ViewModels
{
_config = AppHandler.Instance.Config;
_updateView = updateView;
SortingSelected = _config.ClashUIItem.ConnectionsSorting;
AutoRefresh = _config.ClashUIItem.ConnectionsAutoRefresh;
var canEditRemove = this.WhenAnyValue(
x => x.SelectedSource,
selectedSource => selectedSource != null && Utils.IsNotEmpty(selectedSource.Id));
this.WhenAnyValue(
x => x.SortingSelected,
y => y >= 0)
.Subscribe(async c => await DoSortingSelected(c));
this.WhenAnyValue(
x => x.AutoRefresh,
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()
{
var ret = await ClashApiHandler.Instance.GetClashConnectionsAsync(_config);
@@ -115,7 +92,7 @@ namespace ServiceLib.ViewModels
var dtNow = DateTime.Now;
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}";
if (HostFilter.IsNotEmpty() && !host.Contains(HostFilter))
@@ -131,45 +108,14 @@ namespace ServiceLib.ViewModels
model.Host = host;
var sp = (dtNow - item.start);
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.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);
}
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);
}

View File

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

View File

@@ -1,4 +1,4 @@
using ReactiveUI;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive;
@@ -105,7 +105,7 @@ namespace ServiceLib.ViewModels
item2.DomainStrategy4Freedom = domainStrategy4Freedom2;
item2.DomainDNSAddress = domainDNSAddress2;
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);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);

View File

@@ -219,6 +219,7 @@ namespace ServiceLib.ViewModels
await Reload();
await AutoHideStartup();
Locator.Current.GetService<StatusBarViewModel>()?.RefreshRoutingsMenu();
}
#endregion Init
@@ -266,7 +267,7 @@ namespace ServiceLib.ViewModels
try
{
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);
}
@@ -282,21 +283,23 @@ namespace ServiceLib.ViewModels
try
{
Logging.SaveLog("MyAppExit Begin");
//if (blWindowsShutDown)
await SysProxyHandler.UpdateSysProxy(_config, true);
await ConfigHandler.SaveConfig(_config);
await ProfileExHandler.Instance.SaveTo();
await StatisticsHandler.Instance.SaveTo();
StatisticsHandler.Instance.Close();
CoreHandler.Instance.CoreStop();
await CoreHandler.Instance.CoreStop();
Logging.SaveLog("MyAppExit End");
}
catch { }
finally
{
_updateView?.Invoke(EViewAction.Shutdown, null);
if (!blWindowsShutDown)
{
_updateView?.Invoke(EViewAction.Shutdown, null);
}
}
}
@@ -323,6 +326,7 @@ namespace ServiceLib.ViewModels
if (process.Id > 0)
{
await MyAppExitAsync(false);
await MyAppExitAsync(false);
}
}
@@ -531,6 +535,10 @@ namespace ServiceLib.ViewModels
{
Utils.ProcessStart("nautilus", Utils.GetConfigPath());
}
else if (Utils.IsOSX())
{
Utils.ProcessStart("open", Utils.GetConfigPath());
}
}
#endregion Setting

View File

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

View File

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

View File

@@ -86,7 +86,7 @@ namespace ServiceLib.ViewModels
return;
}
//NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null);
await _updateView?.Invoke(EViewAction.CloseWindow, null);
}
}
}

View File

@@ -7,9 +7,6 @@ namespace ServiceLib.ViewModels
{
public class RoutingSettingViewModel : MyReactiveObject
{
private RoutingItem _lockedItem;
private List<RulesItem> _lockedRules;
#region Reactive
private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>();
@@ -20,12 +17,6 @@ namespace ServiceLib.ViewModels
public IList<RoutingItemModel> SelectedSources { get; set; }
[Reactive]
public bool enableRoutingAdvanced { get; set; }
[Reactive]
public bool enableRoutingBasic { get; set; }
[Reactive]
public string domainStrategy { get; set; }
@@ -35,25 +26,6 @@ namespace ServiceLib.ViewModels
[Reactive]
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> RoutingAdvancedRemoveCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; }
@@ -73,15 +45,6 @@ namespace ServiceLib.ViewModels
x => x.SelectedSource,
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 () =>
{
await RoutingAdvancedEditAsync(true);
@@ -111,67 +74,14 @@ namespace ServiceLib.ViewModels
{
SelectedSource = new();
enableRoutingAdvanced = true;//TODO _config.RoutingBasicItem.EnableRoutingAdvanced;
domainStrategy = _config.RoutingBasicItem.DomainStrategy;
domainMatcher = _config.RoutingBasicItem.DomainMatcher;
domainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox;
await ConfigHandler.InitBuiltinRouting(_config);
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
public async Task RefreshRoutingItems()
@@ -205,12 +115,9 @@ namespace ServiceLib.ViewModels
private async Task SaveRoutingAsync()
{
_config.RoutingBasicItem.DomainStrategy = domainStrategy;
_config.RoutingBasicItem.EnableRoutingAdvanced = enableRoutingAdvanced;
_config.RoutingBasicItem.DomainMatcher = domainMatcher;
_config.RoutingBasicItem.DomainStrategy4Singbox = domainStrategy4Singbox;
await EndBindingLockedData();
if (await ConfigHandler.SaveConfig(_config) == 0)
{
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
@@ -224,18 +131,6 @@ namespace ServiceLib.ViewModels
#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)
{
RoutingItem item;

View File

@@ -108,7 +108,7 @@ namespace ServiceLib.ViewModels
SelectedServer = new();
RunningServerToolTipText = "-";
if (_config.TunModeItem.EnableTun && AppHandler.Instance.IsAdministrator)
if (_config.TunModeItem.EnableTun && AllowEnableTun())
{
EnableTun = true;
}
@@ -347,11 +347,6 @@ namespace ServiceLib.ViewModels
public async Task RefreshRoutingsMenu()
{
_routingItems.Clear();
if (!_config.RoutingBasicItem.EnableRoutingAdvanced)
{
BlRouting = false;
return;
}
BlRouting = true;
var routings = await AppHandler.Instance.RoutingItems();
@@ -414,17 +409,41 @@ namespace ServiceLib.ViewModels
{
_config.TunModeItem.EnableTun = EnableTun;
// When running as a non-administrator, reboot to administrator mode
if (EnableTun && !AppHandler.Instance.IsAdministrator)
if (EnableTun && AllowEnableTun() == false)
{
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
if (Utils.IsWindows())
{
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
}
//else if (Utils.IsLinux())
//{
// NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
//}
}
await ConfigHandler.SaveConfig(_config);
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
}
}
private bool AllowEnableTun()
{
if (Utils.IsWindows())
{
return AppHandler.Instance.IsAdministrator;
}
else if (Utils.IsLinux())
{
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
}
else if (Utils.IsOSX())
{
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
}
return false;
}
#endregion System proxy and Routings
#region UI
@@ -432,19 +451,15 @@ namespace ServiceLib.ViewModels
public async Task InboundDisplayStatus()
{
StringBuilder sb = new();
sb.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}]");
sb.Append(" | ");
sb.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http)}]");
sb.Append($"[{EInboundProtocol.mixed}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}]");
InboundDisplay = $"{ResUI.LabLocal}:{sb}";
if (_config.Inbound[0].AllowLANConn)
if (_config.Inbound.First().AllowLANConn)
{
if (_config.Inbound[0].NewPort4LAN)
if (_config.Inbound.First().NewPort4LAN)
{
StringBuilder sb2 = new();
sb2.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks2)}]");
sb2.Append(" | ");
sb2.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http2)}]");
sb2.Append($"[{EInboundProtocol.mixed}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks2)}]");
InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}";
}
else
@@ -454,7 +469,7 @@ namespace ServiceLib.ViewModels
}
else
{
InboundLanDisplay = $"{ResUI.LabLAN}:None";
InboundLanDisplay = $"{ResUI.LabLAN}:{Global.None}";
}
}

17
v2rayN/build-osx.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
echo 'Building'
OutputPath='./bin/v2rayN'
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o "${OutputPath}/osx-x64"
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o "${OutputPath}/osx-arm64"
rm -rf "$OutputPath/osx-x64/*.pdb"
rm -rf "$OutputPath/osx-arm64/*.pdb"
echo 'Build done'
ls $OutputPath
7z a v2rayN-osx.zip $OutputPath
exit 0

View File

@@ -2,37 +2,57 @@ param (
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]
$OutputPath = '.\bin\v2rayN'
$OutputPath = './bin/v2rayN'
)
Write-Host 'Building'
dotnet publish `
.\v2rayN\v2rayN.csproj `
./v2rayN/v2rayN.csproj `
-c Release `
-r win-x64 `
--self-contained false `
-p:PublishReadyToRun=false `
-p:PublishSingleFile=true `
-o "$OutputPath\win-x64"
-o "$OutputPath/win-x64"
dotnet publish `
.\v2rayN.Desktop\v2rayN.Desktop.csproj `
./v2rayN/v2rayN.csproj `
-c Release `
-r win-arm64 `
--self-contained false `
-p:PublishReadyToRun=false `
-p:PublishSingleFile=true `
-o "$OutputPath/win-arm64"
dotnet publish `
./v2rayN.Desktop/v2rayN.Desktop.csproj `
-c Release `
-r linux-x64 `
--self-contained true `
-p:PublishReadyToRun=false `
-p:PublishSingleFile=true `
-o "$OutputPath\linux-x64"
-o "$OutputPath/linux-x64"
dotnet publish `
./v2rayN.Desktop/v2rayN.Desktop.csproj `
-c Release `
-r linux-arm64 `
--self-contained true `
-p:PublishReadyToRun=false `
-p:PublishSingleFile=true `
-o "$OutputPath/linux-arm64"
if ( -Not $? ) {
exit $lastExitCode
}
if ( Test-Path -Path .\bin\v2rayN ) {
rm -Force "$OutputPath\win-x64\*.pdb"
rm -Force "$OutputPath\linux-x64\*.pdb"
if ( Test-Path -Path ./bin/v2rayN ) {
rm -Force "$OutputPath/win-x64/*.pdb"
rm -Force "$OutputPath/win-arm64/*.pdb"
rm -Force "$OutputPath/linux-x64/*.pdb"
rm -Force "$OutputPath/linux-arm64/*.pdb"
}
Write-Host 'Build done'

View File

@@ -9,8 +9,6 @@ namespace v2rayN.Desktop;
public partial class App : Application
{
//public static EventWaitHandle ProgramStarted;
public override void Initialize()
{
if (!AppHandler.Instance.InitApp())
@@ -32,7 +30,7 @@ public partial class App : Application
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
OnStartup(desktop.Args);
AppHandler.Instance.InitComponents();
desktop.Exit += OnExit;
desktop.MainWindow = new MainWindow();
@@ -41,22 +39,6 @@ public partial class App : Application
base.OnFrameworkInitializationCompleted();
}
private void OnStartup(string[]? Args)
{
var exePathKey = Utils.GetMd5(Utils.GetExePath());
var rebootas = (Args ?? new string[] { }).Any(t => t == Global.RebootAs);
//ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
//if (!rebootas && !bCreatedNew)
//{
// ProgramStarted.Set();
// Environment.Exit(0);
// return;
//}
AppHandler.Instance.InitComponents();
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject != null)
@@ -87,11 +69,12 @@ public partial class App : Application
}
}
private void MenuExit_Click(object? sender, EventArgs e)
private async void MenuExit_Click(object? sender, EventArgs e)
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
Locator.Current.GetService<MainWindowViewModel>()?.MyAppExitAsync(false);
var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null) await service.MyAppExitAsync(false);
desktop.Shutdown();
}

View File

@@ -0,0 +1,19 @@
using Avalonia;
using Avalonia.Media;
using System.Reflection;
namespace v2rayN.Desktop.Common
{
public static class AppBuilderExtension
{
public static AppBuilder WithFontByDefault(this AppBuilder appBuilder)
{
var uri = $"avares://{Assembly.GetExecutingAssembly().GetName().Name}/Assets/Fonts#Noto Sans SC";
return appBuilder.With(new FontManagerOptions()
{
DefaultFamilyName = uri,
FontFallbacks = new[] { new FontFallback { FontFamily = new FontFamily(uri) } }
});
}
}
}

View File

@@ -1,22 +1,56 @@
using Avalonia;
using Avalonia;
using Avalonia.ReactiveUI;
using v2rayN.Desktop.Common;
namespace v2rayN.Desktop;
internal class Program
{
public static EventWaitHandle ProgramStarted;
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static void Main(string[] args)
{
OnStartup(args);
BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}
private static void OnStartup(string[]? Args)
{
if (Utils.IsWindows())
{
var exePathKey = Utils.GetMd5(Utils.GetExePath());
var rebootas = (Args ?? Array.Empty<string>()).Any(t => t == Global.RebootAs);
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
if (!rebootas && !bCreatedNew)
{
ProgramStarted.Set();
Environment.Exit(0);
return;
}
}
else
{
_ = new Mutex(true, "v2rayN", out var bOnlyOneInstance);
if (!bOnlyOneInstance)
{
Environment.Exit(0);
return;
}
}
}
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
//.WithInterFont()
.WithFontByDefault()
.LogToTrace()
.UseReactiveUI();
}

View File

@@ -13,6 +13,7 @@ namespace v2rayN.Desktop.ViewModels
public class ThemeSettingViewModel : MyReactiveObject
{
[Reactive] public bool ColorModeDark { get; set; }
[Reactive] public bool FollowSystemTheme { get; set; }
[Reactive] public int CurrentFontSize { get; set; }
@@ -28,13 +29,14 @@ namespace v2rayN.Desktop.ViewModels
private void RestoreUI()
{
ModifyTheme(_config.UiItem.ColorModeDark);
ModifyTheme();
ModifyFontFamily();
}
private void BindingUI()
{
ColorModeDark = _config.UiItem.ColorModeDark;
FollowSystemTheme = _config.UiItem.FollowSystemTheme;
CurrentFontSize = _config.UiItem.CurrentFontSize;
CurrentLanguage = _config.UiItem.CurrentLanguage;
@@ -44,7 +46,18 @@ namespace v2rayN.Desktop.ViewModels
if (_config.UiItem.ColorModeDark != ColorModeDark)
{
_config.UiItem.ColorModeDark = ColorModeDark;
ModifyTheme(ColorModeDark);
ModifyTheme();
ConfigHandler.SaveConfig(_config);
}
});
this.WhenAnyValue(x => x.FollowSystemTheme,
y => y == true)
.Subscribe(c =>
{
if (_config.UiItem.FollowSystemTheme != FollowSystemTheme)
{
_config.UiItem.FollowSystemTheme = FollowSystemTheme;
ModifyTheme();
ConfigHandler.SaveConfig(_config);
}
});
@@ -59,7 +72,6 @@ namespace v2rayN.Desktop.ViewModels
_config.UiItem.CurrentFontSize = CurrentFontSize;
double size = CurrentFontSize;
ModifyFontSize(size);
ConfigHandler.SaveConfig(_config);
}
});
@@ -79,12 +91,12 @@ namespace v2rayN.Desktop.ViewModels
});
}
private void ModifyTheme(bool isDarkTheme)
private void ModifyTheme()
{
var app = Application.Current;
if (app is not null)
{
app.RequestedThemeVariant = isDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light;
app.RequestedThemeVariant = FollowSystemTheme ? ThemeVariant.Default : (ColorModeDark ? ThemeVariant.Dark : ThemeVariant.Light);
}
}

View File

@@ -112,7 +112,7 @@
x:Name="txtPort"
Grid.Row="3"
Grid.Column="1"
Width="100"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
</Grid>
@@ -164,7 +164,7 @@
x:Name="txtAlterId"
Grid.Row="2"
Grid.Column="1"
Width="100"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
@@ -458,7 +458,7 @@
x:Name="cmbHeaderType8"
Grid.Row="3"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
</Grid>
<Grid
@@ -541,7 +541,7 @@
x:Name="txtShortId9"
Grid.Row="5"
Grid.Column="1"
Width="100"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
</Grid>
@@ -584,7 +584,7 @@
x:Name="cmbNetwork"
Grid.Row="1"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
<TextBlock
Grid.Row="1"
@@ -600,12 +600,50 @@
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbHeaderType}" />
<ComboBox
x:Name="cmbHeaderType"
<StackPanel
Grid.Row="2"
Grid.Column="1"
Width="100"
Classes="Margin8" />
VerticalAlignment="Center"
Orientation="Horizontal">
<ComboBox
x:Name="cmbHeaderType"
Width="200"
Classes="Margin8" />
<Button
x:Name="btnExtra"
Width="30"
Height="30"
Margin="10,0"
Theme="{DynamicResource BorderlessButton}">
<Button.Content>
<PathIcon
Width="20"
Height="20"
Data="{StaticResource building_more}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TransportExtraTip}" />
<TextBox
x:Name="txtExtra"
Width="400"
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin8"
MinLines="6"
TextWrapping="Wrap" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
<TextBlock
x:Name="tipHeaderType"
Grid.Row="2"
@@ -680,7 +718,7 @@
x:Name="cmbStreamSecurity"
Grid.Row="0"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
</Grid>
<Grid
@@ -749,7 +787,7 @@
x:Name="cmbAllowInsecure"
Grid.Row="4"
Grid.Column="1"
Width="100"
Width="200"
Classes="Margin8" />
</Grid>
<Grid

View File

@@ -26,20 +26,10 @@ namespace v2rayN.Desktop.Views
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
if (profileItem.ConfigType == EConfigType.VLESS)
Global.CoreTypes.ForEach(it =>
{
Global.CoreTypes4VLESS.ForEach(it =>
{
cmbCoreType.Items.Add(it);
});
}
else
{
Global.CoreTypes.ForEach(it =>
{
cmbCoreType.Items.Add(it);
});
}
cmbCoreType.Items.Add(it);
});
cmbCoreType.Items.Add(string.Empty);
cmbStreamSecurity.Items.Add(string.Empty);
@@ -208,6 +198,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Extra, v => v.txtExtra.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
@@ -299,6 +290,13 @@ namespace v2rayN.Desktop.Views
cmbHeaderType.Items.Add(it);
});
}
else if (network is nameof(ETransport.xhttp))
{
Global.XhttpMode.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
}
else if (network == nameof(ETransport.grpc))
{
cmbHeaderType.Items.Add(Global.GrpcGunMode);
@@ -319,6 +317,7 @@ namespace v2rayN.Desktop.Views
network = Global.DefaultNetwork;
}
labHeaderType.IsVisible = true;
btnExtra.IsVisible = false;
tipRequestHost.Text =
tipPath.Text =
tipHeaderType.Text = string.Empty;
@@ -337,11 +336,18 @@ namespace v2rayN.Desktop.Views
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
break;
case nameof(ETransport.xhttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip5;
labHeaderType.IsVisible = false;
btnExtra.IsVisible = true;
break;
case nameof(ETransport.h2):
tipRequestHost.Text = ResUI.TransportRequestHostTip3;
tipPath.Text = ResUI.TransportPathTip2;

View File

@@ -39,7 +39,7 @@
<ListBox
x:Name="lstCheckUpdates"
BorderThickness="1"
ItemsSource="{Binding CheckUpdateItems}">
ItemsSource="{Binding CheckUpdateModels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
@@ -50,7 +50,7 @@
<Border
Width="500"
Height="80"
Margin="0"
Margin="-2"
VerticalAlignment="Center"
Theme="{StaticResource CardBorder}">
<Grid>

View File

@@ -15,7 +15,7 @@ namespace v2rayN.Desktop.Views
this.WhenActivated(disposables =>
{
this.OneWayBind(ViewModel, vm => vm.CheckUpdateItems, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.CheckUpdateModels, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdate).DisposeWith(disposables);
@@ -29,7 +29,7 @@ namespace v2rayN.Desktop.Views
case EViewAction.DispatcherCheckUpdate:
if (obj is null) return false;
Dispatcher.UIThread.Post(() =>
ViewModel?.UpdateViewResult((CheckUpdateItem)obj),
ViewModel?.UpdateViewResult((CheckUpdateModel)obj),
DispatcherPriority.Default);
break;

View File

@@ -25,22 +25,6 @@
VerticalContentAlignment="Center"
Watermark="{x:Static resx:ResUI.ConnectionsHostFilterTitle}" />
<TextBlock
Margin="8,0"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSorting}" />
<ComboBox
x:Name="cmbSorting"
Width="100"
Margin="8,0">
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpSpeed}" />
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownSpeed}" />
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpTraffic}" />
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownTraffic}" />
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingTime}" />
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingHost}" />
</ComboBox>
<Button
x:Name="btnConnectionCloseAll"
Width="30"
@@ -58,6 +42,23 @@
</Button.Content>
</Button>
<Button
x:Name="btnAutofitColumnWidth"
Width="30"
Height="30"
Margin="8,0"
Classes="Success"
Theme="{DynamicResource BorderlessButton}"
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
<Button.Content>
<PathIcon
Width="20"
Height="20"
Data="{StaticResource building_fit}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</Button.Content>
</Button>
<TextBlock
Margin="8,0"
VerticalAlignment="Center"
@@ -85,11 +86,11 @@
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn
Width="240"
Width="300"
Binding="{Binding Host}"
Header="{x:Static resx:ResUI.TbSortingHost}" />
<DataGridTextColumn
Width="160"
Width="500"
Binding="{Binding Chain}"
Header="{x:Static resx:ResUI.TbSortingChain}" />
<DataGridTextColumn
@@ -97,17 +98,9 @@
Binding="{Binding Network}"
Header="{x:Static resx:ResUI.TbSortingNetwork}" />
<DataGridTextColumn
Width="100"
Width="160"
Binding="{Binding Type}"
Header="{x:Static resx:ResUI.TbSortingType}" />
<DataGridTextColumn
Width="100"
Binding="{Binding UploadTraffic}"
Header="{x:Static resx:ResUI.TbSortingUpTraffic}" />
<DataGridTextColumn
Width="100"
Binding="{Binding DownloadTraffic}"
Header="{x:Static resx:ResUI.TbSortingDownTraffic}" />
<DataGridTextColumn
Width="100"
Binding="{Binding Elapsed}"

View File

@@ -1,3 +1,4 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
@@ -12,6 +13,7 @@ namespace v2rayN.Desktop.Views
{
InitializeComponent();
ViewModel = new ClashConnectionsViewModel(UpdateViewHandler);
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
this.WhenActivated(disposables =>
{
@@ -22,7 +24,6 @@ namespace v2rayN.Desktop.Views
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
});
@@ -43,6 +44,19 @@ namespace v2rayN.Desktop.Views
return await Task.FromResult(true);
}
private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e)
{
AutofitColumnWidth();
}
private void AutofitColumnWidth()
{
foreach (var it in lstConnections.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}
private void btnClose_Click(object? sender, RoutedEventArgs e)
{
ViewModel?.ClashConnectionClose(false);

View File

@@ -114,7 +114,7 @@
<MenuItem x:Name="menuClose" Padding="8,0">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Static resx:ResUI.menuClose}" />
<TextBlock Text="{x:Static resx:ResUI.menuExit}" />
</StackPanel>
</MenuItem.Header>
</MenuItem>

View File

@@ -7,9 +7,9 @@ using Avalonia.Interactivity;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using DialogHostAvalonia;
using MsBox.Avalonia.Enums;
using ReactiveUI;
using Splat;
using System.ComponentModel;
using System.Reactive.Disposables;
using v2rayN.Desktop.Common;
@@ -21,6 +21,7 @@ namespace v2rayN.Desktop.Views
private WindowNotificationManager? _manager;
private CheckUpdateView? _checkUpdateView;
private BackupAndRestoreView? _backupAndRestoreView;
private bool _blCloseByUser = false;
public MainWindow()
{
@@ -29,21 +30,45 @@ namespace v2rayN.Desktop.Views
_config = AppHandler.Instance.Config;
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
//ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
this.Closing += MainWindow_Closing;
this.KeyDown += MainWindow_KeyDown;
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
menuPromotion.Click += menuPromotion_Click;
menuClose.Click += menuClose_Click;
menuCheckUpdate.Click += MenuCheckUpdate_Click;
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
menuClose.Click += MenuClose_Click;
MessageBus.Current.Listen<string>(EMsgCommand.SendSnackMsg.ToString()).Subscribe(DelegateSnackMsg);
ViewModel = new MainWindowViewModel(UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
//WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
switch (_config.UiItem.MainGirdOrientation)
{
case EGirdOrientation.Horizontal:
tabProfiles.Content ??= new ProfilesView(this);
tabMsgView.Content ??= new MsgView();
tabClashProxies.Content ??= new ClashProxiesView();
tabClashConnections.Content ??= new ClashConnectionsView();
gridMain.IsVisible = true;
break;
case EGirdOrientation.Vertical:
tabProfiles1.Content ??= new ProfilesView(this);
tabMsgView1.Content ??= new MsgView();
tabClashProxies1.Content ??= new ClashProxiesView();
tabClashConnections1.Content ??= new ClashConnectionsView();
gridMain1.IsVisible = true;
break;
case EGirdOrientation.Tab:
default:
tabProfiles2.Content ??= new ProfilesView(this);
tabMsgView2.Content ??= new MsgView();
tabClashProxies2.Content ??= new ClashProxiesView();
tabClashConnections2.Content ??= new ClashConnectionsView();
gridMain2.IsVisible = true;
break;
}
conTheme.Content ??= new ThemeSettingView();
this.WhenActivated(disposables =>
{
@@ -86,7 +111,6 @@ namespace v2rayN.Desktop.Views
switch (_config.UiItem.MainGirdOrientation)
{
case EGirdOrientation.Horizontal:
gridMain.IsVisible = true;
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabMsgView.IsVisible).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies.IsVisible).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections.IsVisible).DisposeWith(disposables);
@@ -94,7 +118,6 @@ namespace v2rayN.Desktop.Views
break;
case EGirdOrientation.Vertical:
gridMain1.IsVisible = true;
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabMsgView1.IsVisible).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies1.IsVisible).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections1.IsVisible).DisposeWith(disposables);
@@ -103,7 +126,6 @@ namespace v2rayN.Desktop.Views
case EGirdOrientation.Tab:
default:
gridMain2.IsVisible = true;
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies2.IsVisible).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections2.IsVisible).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TabMainSelectedIndex, v => v.tabMain2.SelectedIndex).DisposeWith(disposables);
@@ -114,51 +136,35 @@ namespace v2rayN.Desktop.Views
this.Title = $"{Utils.GetVersion()} - {(AppHandler.Instance.IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
if (Utils.IsWindows())
{
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
menuGlobalHotkeySetting.IsVisible = false;
}
else
{
if (AppHandler.Instance.IsAdministrator)
{
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
}
menuRebootAsAdmin.IsVisible = false;
menuSettingsSetUWP.IsVisible = false;
menuGlobalHotkeySetting.IsVisible = false;
}
menuAddServerViaScan.IsVisible = false;
switch (_config.UiItem.MainGirdOrientation)
{
case EGirdOrientation.Horizontal:
tabProfiles.Content ??= new ProfilesView(this);
tabMsgView.Content ??= new MsgView();
tabClashProxies.Content ??= new ClashProxiesView();
tabClashConnections.Content ??= new ClashConnectionsView();
break;
case EGirdOrientation.Vertical:
tabProfiles1.Content ??= new ProfilesView(this);
tabMsgView1.Content ??= new MsgView();
tabClashProxies1.Content ??= new ClashProxiesView();
tabClashConnections1.Content ??= new ClashConnectionsView();
break;
case EGirdOrientation.Tab:
default:
tabProfiles2.Content ??= new ProfilesView(this);
tabMsgView2.Content ??= new MsgView();
tabClashProxies2.Content ??= new ClashProxiesView();
tabClashConnections2.Content ??= new ClashConnectionsView();
break;
}
conTheme.Content ??= new ThemeSettingView();
RestoreUI();
AddHelpMenuItem();
//WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
}
#region Event
private void OnProgramStarted(object state, bool timeout)
{
ShowHideWindow(true);
Dispatcher.UIThread.Post(() =>
ShowHideWindow(true),
DispatcherPriority.Default);
}
private void DelegateSnackMsg(string content)
@@ -271,10 +277,28 @@ namespace v2rayN.Desktop.Views
}
}
private void MainWindow_Closing(object? sender, CancelEventArgs e)
protected override async void OnClosing(WindowClosingEventArgs e)
{
e.Cancel = true;
ShowHideWindow(false);
if (_blCloseByUser)
{
return;
}
Logging.SaveLog("OnClosing -> " + e.CloseReason.ToString());
switch (e.CloseReason)
{
case WindowCloseReason.OwnerWindowClosing or WindowCloseReason.WindowClosing:
e.Cancel = true;
ShowHideWindow(false);
break;
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
await ViewModel?.MyAppExitAsync(true);
break;
}
base.OnClosing(e);
}
private async void MainWindow_KeyDown(object? sender, KeyEventArgs e)
@@ -302,12 +326,6 @@ namespace v2rayN.Desktop.Views
}
}
private void menuClose_Click(object? sender, RoutedEventArgs e)
{
StorageUI();
ShowHideWindow(false);
}
private void menuPromotion_Click(object? sender, RoutedEventArgs e)
{
Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
@@ -355,6 +373,19 @@ namespace v2rayN.Desktop.Views
DialogHost.Show(_backupAndRestoreView);
}
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
{
if (await UI.ShowYesNo(this, ResUI.menuExitTips) == ButtonResult.No)
{
return;
}
_blCloseByUser = true;
StorageUI();
await ViewModel?.MyAppExitAsync(false);
}
#endregion Event
#region UI
@@ -374,8 +405,16 @@ namespace v2rayN.Desktop.Views
}
else
{
this.Hide();
if (_config.UiItem.Hide2TrayWhenClose)
{
this.Hide();
}
else
{
this.WindowState = WindowState.Minimized;
}
}
_config.UiItem.ShowInTaskbar = bl;
}

View File

@@ -83,6 +83,7 @@
Classes="TextArea"
IsReadOnly="True"
TextAlignment="Left"
VerticalAlignment="Stretch"
TextWrapping="Wrap">
<TextBox.ContextMenu>
<ContextMenu>

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