Compare commits

..

139 Commits

Author SHA1 Message Date
2dust
a7de149fd7 up 7.10.0 2025-02-28 09:46:43 +08:00
2dust
ae38be36f5 Checkout submodules 2025-02-27 20:53:29 +08:00
2dust
a20e989211 Update build-windows-desktop.yml 2025-02-27 20:50:52 +08:00
2dust
579f47ba0d Create GlobalHotKeys 2025-02-27 20:25:20 +08:00
2dust
24cad87954 Bug fix
https://github.com/2dust/v2rayN/issues/6812
2025-02-27 20:12:53 +08:00
2dust
84d72cd110 Use project to implement Windows global hotkey
https://github.com/2dust/GlobalHotKeys
2025-02-27 20:12:07 +08:00
2dust
c0cd46a5aa Optimize HotkeyHandler 2025-02-27 17:50:54 +08:00
2dust
98613c43ca Fix tun mtu setting 2025-02-26 20:46:31 +08:00
2dust
555960e210 Optimize and improve code 2025-02-26 17:01:57 +08:00
2dust
a18ae5582b Jump to the selected item when refreshing the server list
https://github.com/2dust/v2rayN/issues/6800
2025-02-26 16:36:36 +08:00
2dust
6d6894591c Update Global.cs 2025-02-26 15:51:47 +08:00
2dust
984b97fc14 Optimize latency and IP address information testing
If the first test fails, it will be tested again after 500ms.
2025-02-26 14:30:10 +08:00
2dust
a7f35d4495 Windows desktop version add global hotkey function 2025-02-26 10:52:36 +08:00
2dust
add92cfa7c Update desktop global hotkey setting 2025-02-25 16:14:50 +08:00
2dust
6079e76be5 Improved global hotkey setting 2025-02-25 14:26:12 +08:00
2dust
166c7cb2f5 Fix window title 2025-02-25 14:15:54 +08:00
nayeko
dbd3ca44c2 Fix Package AppImage script (#6794)
Co-authored-by: nayeko <nayeko@users.noreply.github.com>
2025-02-25 10:06:33 +08:00
dependabot[bot]
ae495dde54 Bump actions/upload-artifact from 4.6.0 to 4.6.1 (#6797)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.6.0 to 4.6.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4.6.0...v4.6.1)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-25 09:46:08 +08:00
2dust
4ae25b2f34 Improved global hotkey setting 2025-02-24 19:53:38 +08:00
2dust
cdfb621c59 Update MsgView.axaml 2025-02-24 19:07:05 +08:00
2dust
29e8df7d2e When set the linux system proxy, use shell scripts instead of command lines 2025-02-24 11:02:51 +08:00
2dust
72ff947d95 Bug fix for ProxySettingOSX 2025-02-23 19:59:01 +08:00
2dust
3edaac5739 When set the macOS system proxy, use shell scripts instead of command lines 2025-02-23 19:52:13 +08:00
2dust
5777a97119 Create proxy_set_osx_sh 2025-02-23 19:41:34 +08:00
2dust
aeddbc1dcc CreateLinuxShellFile in the binConfigs folder 2025-02-23 17:19:45 +08:00
2dust
2f3e409487 Add linux bash param 2025-02-23 16:59:22 +08:00
2dust
aa133bb50b Update SpeedtestService.cs 2025-02-23 16:34:40 +08:00
2dust
3bc79a4ba1 Update 01_bug_report.yml 2025-02-23 12:05:51 +08:00
2dust
064a04fbad up 7.9.3 2025-02-21 17:47:30 +08:00
2dust
39ed13cf8a Create build-all.yml 2025-02-21 17:38:47 +08:00
2dust
a1edacb196 Update UpdateService.cs 2025-02-21 17:37:36 +08:00
2dust
c9f79e4b47 Added update function for Country.mmdb, geoip-only-cn-private.dat, geoip.metadb
https://github.com/2dust/v2rayN/issues/6752
2025-02-21 15:38:11 +08:00
2dust
40c1498226 When testing speed, skip items with incorrect latency 2025-02-21 14:33:43 +08:00
2dust
390061f9bd Fix the desktop UI bug 2025-02-21 12:40:45 +08:00
2dust
42324a2c9e Adjust controls margin 2025-02-20 18:34:25 +08:00
2dust
b9b4ca6360 The desktop version use SemiFontFamilyRegular, Fall back to built-in fonts 2025-02-20 16:23:46 +08:00
2dust
565697bc0b The desktop version unified icon size 2025-02-20 14:32:38 +08:00
2dust
2e6c82c851 Adjust UI
https://github.com/2dust/v2rayN/issues/6751
2025-02-20 14:07:12 +08:00
2dust
ee75dd37af The desktop version add wrap to the subscription group 2025-02-20 11:08:28 +08:00
2dust
4859dcda08 up 7.9.2 2025-02-19 21:10:47 +08:00
2dust
2e962e555d Use AutoCompleteBox instead of editable Combobox for desktop
Thanks to https://github.com/irihitech/Ursa.Avalonia
2025-02-19 17:41:58 +08:00
2dust
ab73e5acb2 Micro-adjustment interface 2025-02-19 17:39:47 +08:00
2dust
4e3e5ce130 Add CanUserReorderColumns for desktop 2025-02-19 15:03:29 +08:00
2dust
bb8eef3bf5 Removed the Hide to tray when closing the window feature for Windows version
https://github.com/2dust/v2rayN/issues/6726
2025-02-19 10:42:31 +08:00
2dust
eee87ded29 Fix cache.db storage location
https://github.com/2dust/v2rayN/issues/6731
2025-02-19 10:06:47 +08:00
2dust
e0f005bd96 up 7.9.1 2025-02-18 18:58:19 +08:00
2dust
2cacc372ad Optimize desktop DataGrid RowHeight adjusts with font size 2025-02-18 18:48:29 +08:00
2dust
0b1b681655 Add system proxy pac to the Windows desktop version 2025-02-18 14:38:08 +08:00
2dust
deafd73306 Optimize RemoveInvalidServerResult 2025-02-17 20:00:28 +08:00
2dust
317a5da120 up build 2025-02-17 14:38:26 +08:00
bonjour
071cefc511 Revert "Fix Package AppImage script (#6681)" (#6714)
This reverts commit 41cc260b5c.
2025-02-17 13:59:36 +08:00
2dust
32a5cc8aa3 Check for avalonia desktop windows version 2025-02-17 12:27:00 +08:00
2dust
c41378a085 Update build-windows-desktop.yml 2025-02-17 12:24:55 +08:00
2dust
6910e03ef4 up 7.9.0 2025-02-16 20:34:14 +08:00
2dust
5060a358db Clear resx 2025-02-16 19:12:58 +08:00
2dust
b3e9a957c4 Remove invalid by test results 2025-02-16 15:07:09 +08:00
2dust
f6dbfc2dac up PackageVersion 2025-02-16 15:05:10 +08:00
2dust
2966a34e63 Update Directory.Build.props 2025-02-16 11:15:32 +08:00
2dust
50959951ae The number of concurrent during multi-test 2025-02-15 20:27:20 +08:00
2dust
c2e1cf7bdb Fix windows TaskbarIcon 2025-02-15 17:26:20 +08:00
2dust
51ac7cc8be Improved and optimized speedtest 2025-02-15 11:21:35 +08:00
2dust
3144f1d1c2 Remove SpeedTestPageSize 2025-02-14 15:00:23 +08:00
2dust
a176e7b912 Optimize the prompt function of speed test
Save friendly prompt information during speed test.
2025-02-14 14:55:43 +08:00
2dust
1198ec0f74 Improved and optimized speedtest
When testing server speed, start the Core for each server and generate the same configuration files as when using the server.
Add a folder binConfigs to store temporary configuration files for Core.
2025-02-13 19:46:51 +08:00
2dust
4104964e38 up 7.8.3 2025-02-12 20:04:29 +08:00
2dust
3bbd1edf06 Update V2rayConfig.cs 2025-02-12 19:18:59 +08:00
lyranico
41cc260b5c Fix Package AppImage script (#6681) 2025-02-12 14:33:02 +08:00
2dust
6cd5063c9b Fix call core file
https://github.com/2dust/v2rayN/issues/6680
2025-02-12 11:23:22 +08:00
2dust
e544df6d01 up 7.8.2 2025-02-11 16:30:16 +08:00
2dust
f952d2383c Remove IncludeNativeLibrariesForSelfExtract 2025-02-11 10:16:19 +08:00
2dust
8a29e147d3 Added Enable Mixin parameter 2025-02-10 20:04:47 +08:00
Alphax-Hue3682
8a19128e7f Update Persian translate (#6651)
* Update Persian translate

* Update ResUI.fa-Ir.resx
2025-02-10 17:40:21 +08:00
2dust
7dc9fbd8ff Improved and optimized speedtest 2025-02-10 10:08:03 +08:00
2dust
31a179e647 Code clean 2025-02-09 20:17:56 +08:00
2dust
c3fdfcc4bd up 7.8.1 2025-02-08 16:49:59 +08:00
2dust
7ea8fae2da Improve test logic
Retest the failed part of the test and call it recursively.
Remove the number of batches that are automatically divided when testing parameters.
2025-02-08 16:43:40 +08:00
2dust
67ffa810d3 Optimize code and remove Action 2025-02-06 15:28:51 +08:00
2dust
ba2a636dd2 Fixed the system language judgment during the first run
https://github.com/2dust/v2rayN/issues/6638
2025-02-06 14:36:38 +08:00
2dust
d471336994 Adjust App Exit function
https://github.com/2dust/v2rayN/issues/6634
2025-02-05 17:31:13 +08:00
2dust
7e6482fdff Adjust hysteria core run arguments
https://github.com/2dust/v2rayN/issues/6635
2025-02-05 17:14:56 +08:00
2dust
a8eba93ffd up 7.8.0 2025-02-04 14:30:42 +08:00
2dust
4ffe595db6 Code clean 2025-02-04 14:30:28 +08:00
2dust
885587e551 Update Directory.Packages.props 2025-02-04 14:19:56 +08:00
2dust
e986dc189e Fix ProcUtils NoAssociatedProcess issue 2025-02-04 10:30:33 +08:00
2dust
bccab41c8f Update Directory.Build.props 2025-02-04 10:28:49 +08:00
2dust
79a0538ca0 Improve core info 2025-02-03 20:19:20 +08:00
2dust
e6b27d17e4 Add support for overtls custom configuration
https://github.com/ShadowsocksR-Live/overtls
2025-02-03 15:43:26 +08:00
2dust
2a0012824a Add support for brook custom configuration
https://github.com/txthinking/brook
https://github.com/txthinking/brook/issues/1372
2025-02-03 15:06:21 +08:00
2dust
9d92be99ee Improve core running arguments 2025-02-03 14:48:53 +08:00
2dust
6914831d30 Code clean 2025-02-02 17:48:59 +08:00
2dust
19d83be6de Fix Package AppImage script 2025-02-01 19:10:54 +08:00
2dust
ce7303bd0d up 7.7.1 2025-02-01 14:16:54 +08:00
2dust
4c3318ac86 Revert "Update MainWindow.axaml.cs"
This reverts commit 4d95d7d8c0.
2025-02-01 14:11:12 +08:00
2dust
db25fdeee1 Revert "Remove using System.Reflection"
This reverts commit 732c3eee8b.
2025-02-01 13:51:28 +08:00
2dust
732c3eee8b Remove using System.Reflection 2025-02-01 10:34:05 +08:00
2dust
2b0d805b2f Update Directory.Build.props 2025-02-01 10:33:11 +08:00
2dust
4faa94b2a3 Cache when reading embedded resources 2025-01-31 16:02:29 +08:00
2dust
331d11aee2 Update .editorconfig 2025-01-31 15:59:44 +08:00
2dust
4d95d7d8c0 Update MainWindow.axaml.cs
if (Utils.IsOSX() || _config.UiItem.Hide2TrayWhenClose)
2025-01-31 15:59:35 +08:00
dependabot[bot]
fd82623c74 Bump actions/setup-dotnet from 4.2.0 to 4.3.0 (#6604)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/actions/setup-dotnet/releases)
- [Commits](https://github.com/actions/setup-dotnet/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: actions/setup-dotnet
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-31 09:17:42 +08:00
2dust
4a32b2c814 Fixed the issue of update the Windows self contained version 2025-01-30 18:06:13 +08:00
2dust
45264005a4 Code clean 2025-01-30 17:10:05 +08:00
2dust
253219dd16 Update .editorconfig 2025-01-30 16:35:48 +08:00
ShiinaRinne
b2feaf3ba9 [macOS] feat: auto run. https://github.com/2dust/v2rayN/issues/6383 (#6597) 2025-01-30 13:24:01 +08:00
2dust
6c5011ad68 Try to remove the tun device when restarting the service in Windows
https://github.com/2dust/v2rayN/pull/6561
2025-01-30 10:46:04 +08:00
ShiinaRinne
c0f8b6b84c [macOS] amend: Child window visibility handling (#6598)
https://github.com/2dust/v2rayN/pull/6596

When the main window is hidden, open child windows are mistakenly hidden as well.
This prevents reopening child windows after the main window is shown again.
2025-01-30 10:12:59 +08:00
ShiinaRinne
f71125d8f3 macOS 一些优化 (#6596)
* [macOS] hide icon in Dock

* [macOS] fix: close button not work

* [macOS] fix: cant directly show window when click `Show or hide the main window` on minimized
2025-01-29 19:26:40 +08:00
2dust
e674a025d8 Adjust Directory.Build.props
https://learn.microsoft.com/zh-cn/dotnet/core/deploying/trimming/trimming-options

https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/compiler-options/code-generation
2025-01-29 15:17:30 +08:00
2dust
dadc24876f Change Directory 2025-01-29 14:22:30 +08:00
Anatoliy
98d4801b7e Use Directory.Build.props for centralized configuration management (#6591)
* use Directory.Buld.props

* remove some properties
2025-01-28 20:01:59 +08:00
Anatoliy
0e50bfb6eb create editorconfig (#6592) 2025-01-28 12:16:04 +08:00
2dust
a5aa286535 Add Name to App.axaml 2025-01-25 20:45:56 +08:00
2dust
3caf025c3c Update README.md 2025-01-25 20:19:02 +08:00
2dust
c943c6c60a Update README.md 2025-01-25 20:15:16 +08:00
2dust
8c55c629cd Fix PackageReference 2025-01-24 20:28:04 +08:00
2dust
0c38ebb63f Added Avalonia UI Windows version compilation script 2025-01-24 20:01:36 +08:00
2dust
75df85f598 Release script adjust prerelease = true 2025-01-24 19:48:34 +08:00
2dust
59e99b2316 Downgrade ZXing.Net.Bindings.SkiaSharp to version 0.16.14
In linux report
Unhandled exception. System.TypeInitializationException: The type initializer for 'SkiaSharp.SKFontManager' threw an exception.
 ---> System.TypeInitializationException: The type initializer for 'SkiaSharp.SKObject' threw an exception.
 ---> System.InvalidOperationException: The version of the native libSkiaSharp library (88.1) is incompatible with this version of SkiaSharp. Supported versions of the native libSkiaSharp library are in the range [116.0, 117.0).
   at SkiaSharp.SkiaSharpVersion.CheckNativeLibraryCompatible(Version minSupported, Version current, Boolean throwIfIncompatible)
   at SkiaSharp.SkiaSharpVersion.CheckNativeLibraryCompatible(Boolean throwIfIncompatible)
   at SkiaSharp.SKObject..cctor()
2025-01-24 19:46:28 +08:00
Anatoliy
02f4dcbaf7 use Directory.Packages.props (#6581) 2025-01-24 19:00:21 +08:00
2dust
470dec5588 up PackageReference 2025-01-24 17:24:07 +08:00
2dust
be1e37ddd0 Hide the upgrade core in Windows 7 2025-01-24 14:26:51 +08:00
2dust
fdc32601a9 Update ResUI.Designer.cs 2025-01-24 14:25:56 +08:00
2dust
d3b86858e1 Revert "Use Directory.Packages.props (#6575)"
This reverts commit 9c20d9cb1f.
2025-01-24 14:25:13 +08:00
Anatoliy
9c20d9cb1f Use Directory.Packages.props (#6575) 2025-01-24 09:57:38 +08:00
alphax-hue3682
d2cda16378 Update Persian Translate (#6559) 2025-01-22 10:00:33 +08:00
aucub
2ab00d5b6f Add Package AppImage script (#6556) 2025-01-21 09:27:38 +08:00
OnceUponATimeInAmerica
1b8a58cd07 Update English translation (#6555) 2025-01-21 09:15:48 +08:00
Anatoliy
0c3293045f Remove extra .gitignore file and move .gitattributes to the root folder for consistent storage of .git-related files. (#6545) 2025-01-20 09:28:30 +08:00
2dust
4c4ce7e8d1 Revert "增加macos dmg软件签名 (#6541)"
This reverts commit a0d4a3f2e8.
2025-01-19 18:58:32 +08:00
zjt003
a0d4a3f2e8 增加macos dmg软件签名 (#6541)
* Update package-osx.sh

* Update build-osx.yml
2025-01-19 18:34:39 +08:00
2dust
26abe7e7d7 up 7.7.0 2025-01-19 09:36:43 +08:00
2dust
b9c86ed3a1 Modify the file name in winget release package 2025-01-19 09:35:19 +08:00
2dust
b7cff66a80 Remove the core name in the Windows release version 2025-01-19 09:34:37 +08:00
2dust
61a40d2860 up PackageReference 2025-01-19 09:27:20 +08:00
2dust
80eb569366 The bin folder is added to the package
54fe669d89
2025-01-18 21:10:41 +08:00
2dust
54fe669d89 Copy the bin folder to the storage location (for init) 2025-01-18 16:58:44 +08:00
2dust
0953237e9e Improvements 2025-01-18 16:01:52 +08:00
2dust
cf1a8599eb When updating the bin folder, skip the file if it already exists.
https://github.com/2dust/v2rayN/issues/6515
2025-01-17 10:27:29 +08:00
alphax-hue3682
171132be12 Update Persian Translate (#6513) 2025-01-16 15:56:05 +08:00
194 changed files with 4974 additions and 3340 deletions

170
.editorconfig Normal file
View File

@@ -0,0 +1,170 @@
root = true
[*]
charset = utf-8
indent_style = space
tab_width = 4
indent_size = 4
end_of_line = crlf
trim_trailing_whitespace = true
insert_final_newline = true
[*.{yml,yaml}]
indent_style = space
indent_size = 2
[*.cs]
dotnet_hide_advanced_members = true
dotnet_member_insertion_location = with_other_members_of_the_same_kind
dotnet_property_generation_behavior = prefer_throwing_properties
dotnet_search_reference_assemblies = true
dotnet_separate_import_directive_groups = false:warning
dotnet_sort_system_directives_first = true:warning
file_header_template = unset
dotnet_style_qualification_for_event = false:warning
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_operators = always_for_clarity:warning
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
dotnet_style_require_accessibility_modifiers = always:warning
dotnet_prefer_system_hash_code = true:warning
dotnet_style_coalesce_expression = true:warning
dotnet_style_collection_initializer = false:warning
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_namespace_match_folder = true:warning
dotnet_style_null_propagation = true:warning
dotnet_style_object_initializer = true:warning
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_collection_expression = false:warning
dotnet_style_prefer_compound_assignment = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = false:warning
dotnet_style_prefer_conditional_expression_over_return = false:warning
dotnet_style_prefer_foreach_explicit_cast_in_source = always:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
dotnet_style_prefer_inferred_tuple_names = true:warning
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
dotnet_style_prefer_simplified_boolean_expressions = true:warning
dotnet_style_prefer_simplified_interpolation = true:warning
dotnet_style_readonly_field = true:warning
dotnet_code_quality_unused_parameters = all:warning
dotnet_remove_unnecessary_suppression_exclusions = none
dotnet_style_allow_multiple_blank_lines_experimental = false:warning
dotnet_style_allow_statement_immediately_after_block_experimental = true:warning
csharp_style_var_elsewhere = true:warning
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_expression_bodied_accessors = when_on_single_line:warning
csharp_style_expression_bodied_constructors = false:warning
csharp_style_expression_bodied_indexers = when_on_single_line:warning
csharp_style_expression_bodied_lambdas = when_on_single_line:warning
csharp_style_expression_bodied_local_functions = false:warning
csharp_style_expression_bodied_methods = false:warning
csharp_style_expression_bodied_operators = false:warning
csharp_style_expression_bodied_properties = when_on_single_line:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_prefer_extended_property_pattern = true:warning
csharp_style_prefer_not_pattern = true:warning
csharp_style_prefer_pattern_matching = true:warning
csharp_style_prefer_switch_expression = false:warning
csharp_style_conditional_delegate_call = true:warning
csharp_prefer_static_anonymous_function = true:warning
csharp_prefer_static_local_function = true:warning
csharp_preferred_modifier_order = public,internal,private,protected,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:warning
csharp_style_prefer_readonly_struct = true:warning
csharp_style_prefer_readonly_struct_member = true:warning
csharp_prefer_braces = true:warning
csharp_prefer_simple_using_statement = true:warning
csharp_prefer_system_threading_lock = true:warning
csharp_style_namespace_declarations = file_scoped:warning
csharp_style_prefer_method_group_conversion = true:warning
csharp_style_prefer_primary_constructors = true:warning
csharp_style_prefer_top_level_statements = false:warning
csharp_prefer_simple_default_expression = true:warning
csharp_style_deconstructed_variable_declaration = true:warning
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
csharp_style_inlined_variable_declaration = true:warning
csharp_style_prefer_index_operator = false:warning
csharp_style_prefer_local_over_anonymous_function = true:warning
csharp_style_prefer_null_check_over_type_check = true:warning
csharp_style_prefer_range_operator = false:warning
csharp_style_prefer_tuple_swap = true:warning
csharp_style_prefer_utf8_string_literals = true:warning
csharp_style_throw_expression = true:warning
csharp_style_unused_value_assignment_preference = discard_variable:warning
csharp_style_unused_value_expression_statement_preference = discard_variable:warning
csharp_using_directive_placement = outside_namespace:warning
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:warning
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:warning
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false:warning
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:warning
csharp_style_allow_embedded_statements_on_same_line_experimental = false:warning
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_labels = no_change
csharp_indent_switch_labels = true
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = false:warning
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = false
dotnet_naming_rule.interface_should_be_pascal.severity = warning
dotnet_naming_rule.interface_should_be_pascal.symbols = interface
dotnet_naming_rule.interface_should_be_pascal.style = pascal
dotnet_naming_rule.types_should_be_pascal.severity = warning
dotnet_naming_rule.types_should_be_pascal.symbols = types
dotnet_naming_rule.types_should_be_pascal.style = pascal
dotnet_naming_rule.non_field_members_should_be_pascal.severity = warning
dotnet_naming_rule.non_field_members_should_be_pascal.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal.style = pascal
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = *
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = *
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = *
dotnet_naming_symbols.non_field_members.required_modifiers =
dotnet_naming_style.pascal.required_prefix =
dotnet_naming_style.pascal.required_suffix =
dotnet_naming_style.pascal.word_separator =
dotnet_naming_style.pascal.capitalization = pascal_case

View File

@@ -3,6 +3,13 @@ description: 在提出问题前请先自行排除服务器端问题和升级到
title: "[Bug]: " title: "[Bug]: "
labels: ["bug"] labels: ["bug"]
body: body:
- type: input
id: "os-version"
attributes:
label: "操作系统和版本"
description: "操作系统和版本"
validations:
required: true
- type: input - type: input
id: "expectation" id: "expectation"
attributes: attributes:

View File

@@ -1,10 +1,11 @@
# Set update schedule for GitHub Actions
version: 2 version: 2
updates: updates:
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
directory: "/" directory: "/"
schedule: schedule:
# Check for updates to GitHub Actions every daily interval: "daily"
- package-ecosystem: "nuget"
directory: "/"
schedule:
interval: "daily" interval: "daily"

69
.github/workflows/build-all.yml vendored Normal file
View File

@@ -0,0 +1,69 @@
name: release all platforms
on:
workflow_dispatch:
inputs:
release_tag:
required: false
type: string
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Trigger build windows
if: github.event.inputs.release_tag != ''
run: |
curl -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows.yml/dispatches \
-d "{
\"ref\": \"master\",
\"inputs\": {
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
}
}"
- name: Trigger build linux
if: github.event.inputs.release_tag != ''
run: |
curl -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-linux.yml/dispatches \
-d "{
\"ref\": \"master\",
\"inputs\": {
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
}
}"
- name: Trigger build osx
if: github.event.inputs.release_tag != ''
run: |
curl -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-osx.yml/dispatches \
-d "{
\"ref\": \"master\",
\"inputs\": {
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
}
}"
- name: Trigger build windows desktop
if: github.event.inputs.release_tag != ''
run: |
curl -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows-desktop.yml/dispatches \
-d "{
\"ref\": \"master\",
\"inputs\": {
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
}
}"

View File

@@ -22,22 +22,30 @@ jobs:
matrix: matrix:
configuration: [Release] configuration: [Release]
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
with:
submodules: 'recursive'
fetch-depth: '0'
- name: Setup
uses: actions/setup-dotnet@v4.3.0
with:
dotnet-version: '8.0.x'
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained=true -o $OutputPath64
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4.6.1
with: with:
name: v2rayN-linux name: v2rayN-linux
path: | path: |
@@ -58,6 +66,22 @@ jobs:
file: ${{ github.workspace }}/v2rayN*.deb file: ${{ github.workspace }}/v2rayN*.deb
tag: ${{ github.event.inputs.release_tag }} tag: ${{ github.event.inputs.release_tag }}
file_glob: true file_glob: true
prerelease: true
- name: Package AppImage
if: github.event.inputs.release_tag != ''
run: |
chmod a+x package-appimage.sh
./package-appimage.sh
- name: Upload AppImage to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.AppImage
tag: ${{ github.event.inputs.release_tag }}
file_glob: true
prerelease: true
# release zip archive # release zip archive
- name: Package release zip archive - name: Package release zip archive

View File

@@ -26,18 +26,26 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
with:
submodules: 'recursive'
fetch-depth: '0'
- name: Setup
uses: actions/setup-dotnet@v4.3.0
with:
dotnet-version: '8.0.x'
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPath64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained=true -o $OutputPath64
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -o $OutputPathArm64 dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4.6.1
with: with:
name: v2rayN-macos name: v2rayN-macos
path: | path: |
@@ -59,6 +67,7 @@ jobs:
file: ${{ github.workspace }}/v2rayN*.dmg file: ${{ github.workspace }}/v2rayN*.dmg
tag: ${{ github.event.inputs.release_tag }} tag: ${{ github.event.inputs.release_tag }}
file_glob: true file_glob: true
prerelease: true
# release zip archive # release zip archive
- name: Package release zip archive - name: Package release zip archive

View File

@@ -0,0 +1,71 @@
name: release Windows desktop (Avalonia UI)
on:
workflow_dispatch:
inputs:
release_tag:
required: false
type: string
push:
branches:
- master
env:
OutputArch: "windows-64"
OutputArchArm: "windows-arm64"
OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64"
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64"
jobs:
build:
strategy:
matrix:
configuration: [Release]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
with:
submodules: 'recursive'
fetch-depth: '0'
- name: Setup
uses: actions/setup-dotnet@v4.3.0
with:
dotnet-version: '8.0.x'
- name: Build
run: |
cd v2rayN
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
- name: Upload build artifacts
uses: actions/upload-artifact@v4.6.1
with:
name: v2rayN-windows-desktop
path: |
${{ github.workspace }}/v2rayN/Release/windows*
# release zip archive
- name: Package release zip archive
if: github.event.inputs.release_tag != ''
run: |
chmod 755 package-release-zip.sh
./package-release-zip.sh $OutputArch $OutputPath64
mv "v2rayN-${OutputArch}.zip" "v2rayN-${OutputArch}-desktop.zip"
./package-release-zip.sh $OutputArchArm $OutputPathArm64
mv "v2rayN-${OutputArchArm}.zip" "v2rayN-${OutputArchArm}-desktop.zip"
- name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.zip
tag: ${{ github.event.inputs.release_tag }}
file_glob: true
prerelease: true

View File

@@ -27,26 +27,26 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
- name: Setup - name: Setup
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4.3.0
with: with:
dotnet-version: '8.0.x' dotnet-version: '8.0.x'
- name: Build - name: Build
run: | run: |
cd v2rayN cd v2rayN
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained false -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:EnableWindowsTargeting=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4.6.1
with: with:
name: v2rayN-windows name: v2rayN-windows
path: | path: |
@@ -58,10 +58,8 @@ jobs:
run: | run: |
chmod 755 package-release-zip.sh chmod 755 package-release-zip.sh
./package-release-zip.sh $OutputArch $OutputPath64 ./package-release-zip.sh $OutputArch $OutputPath64
./package-release-zip.sh "windows-64-With-Core" $OutputPath64
./package-release-zip.sh $OutputArchArm $OutputPathArm64 ./package-release-zip.sh $OutputArchArm $OutputPathArm64
./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc ./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc
./package-release-zip.sh "windows-64-SelfContained-With-Core" $OutputPath64Sc
- name: Upload zip archive to release - name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2

View File

@@ -22,7 +22,7 @@ jobs:
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases" $github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1 $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 $installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip*' | Select -ExpandProperty browser_download_url
$ver = $targetRelease.tag_name $ver = $targetRelease.tag_name

415
.gitignore vendored
View File

@@ -1,19 +1,400 @@
################################################################################ ## Ignore Visual Studio temporary files, build results, and
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。 ## files generated by popular Visual Studio add-ons.
################################################################################ ##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
/v2rayN/.vs/ # User-specific files
/v2rayN/v2rayN/bin/Debug/app.publish *.rsuser
/v2rayN/v2rayN/bin/Debug *.suo
/v2rayN/v2rayN/bin/Release
/v2rayN/v2rayN/obj/
/v2rayN/.vs/v2rayN/DesignTimeBuild
/v2rayN/packages
.vs/ProjectSettings.json
.vs/slnx.sqlite
.vs/VSWorkspaceState.json
/v2rayN/v2rayUpgrade/bin/Debug
/v2rayN/v2rayUpgrade/bin/Release
/v2rayN/v2rayUpgrade/obj/
*.user *.user
/.vs/v2rayN *.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
# but not Directory.Build.rsp, as it configures directory-level build defaults
!Directory.Build.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "v2rayN/GlobalHotKeys"]
path = v2rayN/GlobalHotKeys
url = https://github.com/2dust/GlobalHotKeys

View File

@@ -1,5 +1,5 @@
# v2rayN # v2rayN
A GUI client for Windows, Linux and macOS, support [Xray core](https://github.com/XTLS/Xray-core) and [sing-box-core](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) A GUI client for Windows, Linux and macOS, support [Xray](https://github.com/XTLS/Xray-core) and [sing-box](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master) [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master)
@@ -9,26 +9,8 @@ A GUI client for Windows, Linux and macOS, support [Xray core](https://github.co
## How to use ## How to use
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` under user permissions
```
Debian 9+
Ubuntu 16.04+
Fedora 30+
```
### macOS
- `chmod +x v2rayN` Run `./v2rayN` under user permissions
```
macOS 11+
```
## Requirements
- [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)
Read the [Wiki](https://github.com/2dust/v2rayN/wiki) for details.
## Telegram Channel ## Telegram Channel
[github_2dust](https://t.me/github_2dust) [github_2dust](https://t.me/github_2dust)

14
package-appimage.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
sudo apt update -y
sudo apt install -y libfuse2
wget -O pkg2appimage https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage
chmod a+x pkg2appimage
export AppImageOutputArch=$OutputArch
export OutputPath=$OutputPath64
./pkg2appimage ./pkg2appimage.yml
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage
export AppImageOutputArch=$OutputArchArm
export OutputPath=$OutputPathArm64
./pkg2appimage ./pkg2appimage.yml
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage

View File

@@ -4,6 +4,11 @@ Arch="$1"
OutputPath="$2" OutputPath="$2"
Version="$3" Version="$3"
FileName="v2rayN-${Arch}.zip"
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
7z x $FileName
cp -rf v2rayN-${Arch}/* $OutputPath
PackagePath="v2rayN-Package-${Arch}" PackagePath="v2rayN-Package-${Arch}"
mkdir -p "${PackagePath}/DEBIAN" mkdir -p "${PackagePath}/DEBIAN"
mkdir -p "${PackagePath}/opt" mkdir -p "${PackagePath}/opt"

View File

@@ -4,6 +4,11 @@ Arch="$1"
OutputPath="$2" OutputPath="$2"
Version="$3" Version="$3"
FileName="v2rayN-${Arch}.zip"
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
7z x $FileName
cp -rf v2rayN-${Arch}/* $OutputPath
PackagePath="v2rayN-Package-${Arch}" PackagePath="v2rayN-Package-${Arch}"
mkdir -p "$PackagePath/v2rayN.app/Contents/Resources" mkdir -p "$PackagePath/v2rayN.app/Contents/Resources"
cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS" cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS"

37
pkg2appimage.yml Normal file
View File

@@ -0,0 +1,37 @@
app: v2rayN
binpatch: true
ingredients:
script:
- export FileName="v2rayN-${AppImageOutputArch}.zip"
- wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/${FileName}"
- 7z x $FileName -aoa
- cp -rf v2rayN-${AppImageOutputArch}/* $OutputPath
script:
- mkdir -p usr/bin usr/lib
- cp -rf $OutputPath usr/lib/v2rayN
- echo "When this file exists, app will not store configs under this folder" > usr/lib/v2rayN/NotStoreConfigHere.txt
- ln -sf usr/lib/v2rayN/v2rayN usr/bin/v2rayN
- chmod a+x usr/lib/v2rayN/v2rayN
- find usr -type f -exec sh -c 'file "{}" | grep -qi "executable" && chmod +x "{}"' \;
- install -Dm644 usr/lib/v2rayN/v2rayN.png v2rayN.png
- install -Dm644 usr/lib/v2rayN/v2rayN.png usr/share/pixmaps/v2rayN.png
- cat > v2rayN.desktop <<EOF
- [Desktop Entry]
- Name=v2rayN
- Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
- Exec=v2rayN
- Icon=v2rayN
- Terminal=false
- Type=Application
- Categories=Network;
- EOF
- install -Dm644 v2rayN.desktop usr/share/applications/v2rayN.desktop
- cat > AppRun <<\EOF
- #!/bin/sh
- HERE="$(dirname "$(readlink -f "${0}")")"
- cd ${HERE}/usr/lib/v2rayN
- exec ${HERE}/usr/lib/v2rayN/v2rayN $@
- EOF
- chmod a+x AppRun

363
v2rayN/.gitignore vendored
View File

@@ -1,363 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd

View File

@@ -2,14 +2,14 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Copyright>Copyright © 2017-2025 (GPLv3)</Copyright>
<FileVersion>1.3.1</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Update="Resx\Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
</EmbeddedResource>
<Compile Update="Resx\Resource.Designer.cs"> <Compile Update="Resx\Resource.Designer.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
@@ -17,11 +17,4 @@
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resx\Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project> </Project>

View File

@@ -1,4 +1,4 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO.Compression; using System.IO.Compression;
using System.Text; using System.Text;
@@ -10,7 +10,7 @@ namespace AmazTool
{ {
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}"); Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
Waiting(5); Utils.Waiting(5);
if (!File.Exists(fileName)) if (!File.Exists(fileName))
{ {
@@ -42,12 +42,12 @@ namespace AmazTool
StringBuilder sb = new(); StringBuilder sb = new();
try try
{ {
string thisAppOldFile = $"{Utils.GetExePath()}.tmp"; var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
File.Delete(thisAppOldFile); File.Delete(thisAppOldFile);
string splitKey = "/"; var splitKey = "/";
using ZipArchive archive = ZipFile.OpenRead(fileName); using var archive = ZipFile.OpenRead(fileName);
foreach (ZipArchiveEntry entry in archive.Entries) foreach (var entry in archive.Entries)
{ {
try try
{ {
@@ -59,16 +59,22 @@ namespace AmazTool
Console.WriteLine(entry.FullName); Console.WriteLine(entry.FullName);
var lst = entry.FullName.Split(splitKey); var lst = entry.FullName.Split(splitKey);
if (lst.Length == 1) continue; if (lst.Length == 1)
string fullName = string.Join(splitKey, lst[1..lst.Length]); continue;
var fullName = string.Join(splitKey, lst[1..lst.Length]);
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase)) if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
{ {
File.Move(Utils.GetExePath(), thisAppOldFile); File.Move(Utils.GetExePath(), thisAppOldFile);
} }
string entryOutputPath = Utils.GetPath(fullName); var entryOutputPath = Utils.GetPath(fullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!); Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
//In the bin folder, if the file already exists, it will be skipped
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
{
continue;
}
entry.ExtractToFile(entryOutputPath, true); entry.ExtractToFile(entryOutputPath, true);
Console.WriteLine(entryOutputPath); Console.WriteLine(entryOutputPath);
@@ -91,18 +97,9 @@ namespace AmazTool
} }
Console.WriteLine(Resx.Resource.Restartv2rayN); Console.WriteLine(Resx.Resource.Restartv2rayN);
Waiting(2); Utils.Waiting(2);
Utils.StartV2RayN(); Utils.StartV2RayN();
} }
public static void Waiting(int second)
{
for (var i = second; i > 0; i--)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
}
} }
} }

View File

@@ -39,5 +39,14 @@ namespace AmazTool
}; };
process.Start(); process.Start();
} }
public static void Waiting(int second)
{
for (var i = second; i > 0; i--)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
}
} }
} }

View File

@@ -0,0 +1,33 @@
<Project>
<PropertyGroup>
<Version>7.10.0</Version>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<NoWarn>CA1031;CS1591;NU1507;CA1416</NoWarn>
<Nullable>annotations</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Authors>2dust</Authors>
<PackageLicenseExpression>GPL-3.0</PackageLicenseExpression>
<Copyright>Copyright © 2017-$([System.DateTime]::UtcNow.Year) $(Authors)</Copyright>
<InvariantGlobalization>false</InvariantGlobalization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>embedded</DebugType>
<EventSourceSupport>false</EventSourceSupport>
<StackTraceSupport>false</StackTraceSupport>
<MetricsSupport>false</MetricsSupport>
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
<UseSystemResourceKeys>true</UseSystemResourceKeys>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>false</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,30 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.4" />
<PackageVersion Include="Avalonia.Desktop" Version="11.2.4" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.4" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.4" />
<PackageVersion Include="CliWrap" Version="3.8.1" />
<PackageVersion Include="Downloader" Version="3.3.3" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" />
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
<PackageVersion Include="QRCoder" Version="1.6.0" />
<PackageVersion Include="ReactiveUI" Version="20.1.63" />
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageVersion Include="ReactiveUI.WPF" Version="20.1.63" />
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.4" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.4" />
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.0" />
<PackageVersion Include="WebDav.Client" Version="2.8.0" />
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
</ItemGroup>
</Project>

1
v2rayN/GlobalHotKeys Submodule

Submodule v2rayN/GlobalHotKeys added at 35901e2eaa

View File

@@ -1,5 +1,5 @@
using Downloader;
using System.Net; using System.Net;
using Downloader;
namespace ServiceLib.Common namespace ServiceLib.Common
{ {

View File

@@ -0,0 +1,61 @@
using System.Collections.Concurrent;
using System.Reflection;
namespace ServiceLib.Common;
public static class EmbedUtils
{
private static readonly string _tag = "EmbedUtils";
private static readonly ConcurrentDictionary<string, string> _dicEmbedCache = new();
/// <summary>
/// Get embedded text resources
/// </summary>
/// <param name="res"></param>
/// <returns></returns>
public static string GetEmbedText(string res)
{
if (_dicEmbedCache.TryGetValue(res, out var value))
{
return value;
}
var result = string.Empty;
try
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(res);
ArgumentNullException.ThrowIfNull(stream);
using StreamReader reader = new(stream);
result = reader.ReadToEnd();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
_dicEmbedCache.TryAdd(res, result);
return result;
}
/// <summary>
/// Get local storage resources
/// </summary>
/// <returns></returns>
public static string? LoadResource(string? res)
{
try
{
if (File.Exists(res))
{
return File.ReadAllText(res);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return null;
}
}

View File

@@ -156,7 +156,7 @@ namespace ServiceLib.Common
return true; return true;
} }
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, string? ignoredName) public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, bool overwrite, string? ignoredName = null)
{ {
// Get information about the source directory // Get information about the source directory
var dir = new DirectoryInfo(sourceDir); var dir = new DirectoryInfo(sourceDir);
@@ -183,7 +183,11 @@ namespace ServiceLib.Common
continue; continue;
} }
var targetFilePath = Path.Combine(destinationDir, file.Name); var targetFilePath = Path.Combine(destinationDir, file.Name);
file.CopyTo(targetFilePath, true); if (!overwrite && File.Exists(targetFilePath))
{
continue;
}
file.CopyTo(targetFilePath, overwrite);
} }
// If recursive and copying subdirectories, recursively call this method // If recursive and copying subdirectories, recursively call this method
@@ -192,7 +196,7 @@ namespace ServiceLib.Common
foreach (var subDir in dirs) foreach (var subDir in dirs)
{ {
var newDestinationDir = Path.Combine(destinationDir, subDir.Name); var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
CopyDirectory(subDir.FullName, newDestinationDir, true, ignoredName); CopyDirectory(subDir.FullName, newDestinationDir, true, overwrite, ignoredName);
} }
} }
} }

View File

@@ -38,13 +38,15 @@ namespace ServiceLib.Common
public async Task<string?> GetAsync(string url) public async Task<string?> GetAsync(string url)
{ {
if (Utils.IsNullOrEmpty(url)) return null; if (Utils.IsNullOrEmpty(url))
return null;
return await httpClient.GetStringAsync(url); return await httpClient.GetStringAsync(url);
} }
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default) public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
{ {
if (Utils.IsNullOrEmpty(url)) return null; if (Utils.IsNullOrEmpty(url))
return null;
return await client.GetStringAsync(url, token); return await client.GetStringAsync(url, token);
} }
@@ -75,11 +77,13 @@ namespace ServiceLib.Common
{ {
ArgumentNullException.ThrowIfNull(url); ArgumentNullException.ThrowIfNull(url);
ArgumentNullException.ThrowIfNull(fileName); ArgumentNullException.ThrowIfNull(fileName);
if (File.Exists(fileName)) File.Delete(fileName); if (File.Exists(fileName))
File.Delete(fileName);
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token); using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString()); if (!response.IsSuccessStatusCode)
throw new Exception(response.StatusCode.ToString());
var total = response.Content.Headers.ContentLength ?? -1L; var total = response.Content.Headers.ContentLength ?? -1L;
var canReportProgress = total != -1 && progress != null; var canReportProgress = total != -1 && progress != null;
@@ -97,7 +101,8 @@ namespace ServiceLib.Common
var read = await stream.ReadAsync(buffer, token); var read = await stream.ReadAsync(buffer, token);
totalRead += read; totalRead += read;
if (read == 0) break; if (read == 0)
break;
await file.WriteAsync(buffer.AsMemory(0, read), token); await file.WriteAsync(buffer.AsMemory(0, read), token);
if (canReportProgress) if (canReportProgress)

View File

@@ -1,4 +1,4 @@
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace ServiceLib.Common namespace ServiceLib.Common
@@ -75,7 +75,8 @@ namespace ServiceLib.Common
private void Dispose(bool disposing) private void Dispose(bool disposing)
{ {
if (disposed) return; if (disposed)
return;
disposed = true; disposed = true;
if (disposing) if (disposing)

View File

@@ -1,4 +1,4 @@
using NLog; using NLog;
using NLog.Config; using NLog.Config;
using NLog.Targets; using NLog.Targets;
@@ -27,14 +27,16 @@ namespace ServiceLib.Common
public static void SaveLog(string strContent) public static void SaveLog(string strContent)
{ {
if (!LogManager.IsLoggingEnabled()) return; if (!LogManager.IsLoggingEnabled())
return;
LogManager.GetLogger("Log1").Info(strContent); LogManager.GetLogger("Log1").Info(strContent);
} }
public static void SaveLog(string strTitle, Exception ex) public static void SaveLog(string strTitle, Exception ex)
{ {
if (!LogManager.IsLoggingEnabled()) return; if (!LogManager.IsLoggingEnabled())
return;
var logger = LogManager.GetLogger("Log2"); var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}"); logger.Debug($"{strTitle},{ex.Message}");

View File

@@ -19,21 +19,27 @@ public static class ProcUtils
} }
try try
{ {
if (fileName.Contains(' ')) fileName = fileName.AppendQuotes(); if (fileName.Contains(' '))
if (arguments.Contains(' ')) arguments = arguments.AppendQuotes(); {
fileName = fileName.AppendQuotes();
}
if (arguments.Contains(' '))
{
arguments = arguments.AppendQuotes();
}
Process process = new() Process proc = new()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
{ {
UseShellExecute = true, UseShellExecute = true,
FileName = fileName, FileName = fileName,
Arguments = arguments, Arguments = arguments,
WorkingDirectory = dir WorkingDirectory = dir ?? string.Empty
} }
}; };
process.Start(); proc.Start();
return process.Id; return dir is null ? null : proc.Id;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -83,10 +89,44 @@ public static class ProcUtils
GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName); GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName);
try { proc?.Kill(true); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } try
try { proc?.Kill(); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } {
try { proc?.Close(); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } if (Utils.IsNonWindows())
try { proc?.Dispose(); } catch (Exception ex) { Logging.SaveLog(_tag, ex); } {
proc?.Kill(true);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
try
{
proc?.Kill();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
try
{
proc?.Close();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
try
{
proc?.Dispose();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
await Task.Delay(300); await Task.Delay(300);
await ProcessKillByKeyInfo(review, procId, fileName, processName); await ProcessKillByKeyInfo(review, procId, fileName, processName);
@@ -97,7 +137,8 @@ public static class ProcUtils
procId = null; procId = null;
fileName = null; fileName = null;
processName = null; processName = null;
if (!review) return; if (!review)
return;
try try
{ {
procId = proc?.Id; procId = proc?.Id;

View File

@@ -1,5 +1,5 @@
using SQLite;
using System.Collections; using System.Collections;
using SQLite;
namespace ServiceLib.Common namespace ServiceLib.Common
{ {

View File

@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace ServiceLib.Common namespace ServiceLib.Common
{ {
@@ -21,7 +21,8 @@ namespace ServiceLib.Common
public static bool BeginWithAny(this string s, IEnumerable<char> chars) public static bool BeginWithAny(this string s, IEnumerable<char> chars)
{ {
if (s.IsNullOrEmpty()) return false; if (s.IsNullOrEmpty())
return false;
return chars.Contains(s.First()); return chars.Contains(s.First());
} }
@@ -34,7 +35,8 @@ namespace ServiceLib.Common
{ {
while (reader.ReadLine() is { } line) while (reader.ReadLine() is { } line)
{ {
if (line.IsWhiteSpace()) continue; if (line.IsWhiteSpace())
continue;
yield return line; yield return line;
} }
} }

View File

@@ -1,5 +1,3 @@
using CliWrap;
using CliWrap.Buffered;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
using System.Net; using System.Net;
@@ -10,6 +8,8 @@ using System.Runtime.InteropServices;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Principal; using System.Security.Principal;
using System.Text; using System.Text;
using CliWrap;
using CliWrap.Buffered;
namespace ServiceLib.Common namespace ServiceLib.Common
{ {
@@ -17,56 +17,6 @@ namespace ServiceLib.Common
{ {
private static readonly string _tag = "Utils"; private static readonly string _tag = "Utils";
#region
/// <summary>
/// 获取嵌入文本资源
/// </summary>
/// <param name="res"></param>
/// <returns></returns>
public static string GetEmbedText(string res)
{
var result = string.Empty;
try
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(res);
ArgumentNullException.ThrowIfNull(stream);
using StreamReader reader = new(stream);
result = reader.ReadToEnd();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return result;
}
/// <summary>
/// 取得存储资源
/// </summary>
/// <returns></returns>
public static string? LoadResource(string? res)
{
try
{
if (File.Exists(res))
{
return File.ReadAllText(res);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return null;
}
#endregion
#region #region
/// <summary> /// <summary>
@@ -176,7 +126,8 @@ namespace ServiceLib.Common
{ {
try try
{ {
if (plainText.IsNullOrEmpty()) return ""; if (plainText.IsNullOrEmpty())
return "";
plainText = plainText.Trim() plainText = plainText.Trim()
.Replace(Environment.NewLine, "") .Replace(Environment.NewLine, "")
.Replace("\n", "") .Replace("\n", "")
@@ -372,7 +323,8 @@ namespace ServiceLib.Common
public static bool IsBase64String(string? plainText) public static bool IsBase64String(string? plainText)
{ {
if (plainText.IsNullOrEmpty()) return false; if (plainText.IsNullOrEmpty())
return false;
var buffer = new Span<byte>(new byte[plainText.Length]); var buffer = new Span<byte>(new byte[plainText.Length]);
return Convert.TryFromBase64String(plainText, buffer, out var _); return Convert.TryFromBase64String(plainText, buffer, out var _);
} }
@@ -462,9 +414,12 @@ namespace ServiceLib.Common
if (IPAddress.TryParse(ip, out var address)) if (IPAddress.TryParse(ip, out var address))
{ {
var ipBytes = address.GetAddressBytes(); var ipBytes = address.GetAddressBytes();
if (ipBytes[0] == 10) return true; if (ipBytes[0] == 10)
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true; return true;
if (ipBytes[0] == 192 && ipBytes[1] == 168) return true; if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31)
return true;
if (ipBytes[0] == 192 && ipBytes[1] == 168)
return true;
} }
return false; return false;
@@ -478,10 +433,22 @@ namespace ServiceLib.Common
{ {
try try
{ {
var ipProperties = IPGlobalProperties.GetIPGlobalProperties(); List<IPEndPoint> lstIpEndPoints = new();
var ipEndPoints = ipProperties.GetActiveTcpListeners(); List<TcpConnectionInformation> lstTcpConns = new();
//var lstIpEndPoints = new List<IPEndPoint>(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
return ipEndPoints.Any(endPoint => endPoint.Port == port); lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
if (lstIpEndPoints?.FindIndex(it => it.Port == port) >= 0)
{
return true;
}
if (lstTcpConns?.FindIndex(it => it.LocalEndPoint.Port == port) >= 0)
{
return true;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -519,7 +486,7 @@ namespace ServiceLib.Common
public static bool UpgradeAppExists(out string upgradeFileName) public static bool UpgradeAppExists(out string upgradeFileName)
{ {
upgradeFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, GetExeName("AmazTool")); upgradeFileName = Path.Combine(GetBaseDirectory(), GetExeName("AmazTool"));
return File.Exists(upgradeFileName); return File.Exists(upgradeFileName);
} }
@@ -604,9 +571,11 @@ namespace ServiceLib.Common
foreach (var host in hostsList) foreach (var host in hostsList)
{ {
if (host.StartsWith("#")) continue; if (host.StartsWith("#"))
continue;
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (hostItem.Length != 2) continue; if (hostItem.Length != 2)
continue;
systemHosts.Add(hostItem.Last(), hostItem.First()); systemHosts.Add(hostItem.Last(), hostItem.First());
} }
} }
@@ -666,12 +635,12 @@ namespace ServiceLib.Common
try try
{ {
//When this file exists, it is equivalent to having no permission to read and write //When this file exists, it is equivalent to having no permission to read and write
if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "NotStoreConfigHere.txt"))) if (File.Exists(Path.Combine(GetBaseDirectory(), "NotStoreConfigHere.txt")))
{ {
return false; return false;
} }
var tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "guiTemps"); var tempPath = Path.Combine(GetBaseDirectory(), "guiTemps");
if (!Directory.Exists(tempPath)) if (!Directory.Exists(tempPath))
{ {
Directory.CreateDirectory(tempPath); Directory.CreateDirectory(tempPath);
@@ -699,6 +668,11 @@ namespace ServiceLib.Common
return Path.Combine(startupPath, fileName); return Path.Combine(startupPath, fileName);
} }
public static string GetBaseDirectory(string fileName = "")
{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
}
public static string GetExePath() public static string GetExePath()
{ {
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty; return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
@@ -706,12 +680,12 @@ namespace ServiceLib.Common
public static string StartupPath() public static string StartupPath()
{ {
if (Utils.IsNonWindows() && Environment.GetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA") == "1") if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
{ {
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "v2rayN"); return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "v2rayN");
} }
return AppDomain.CurrentDomain.BaseDirectory; return GetBaseDirectory();
} }
public static string GetTempPath(string filename = "") public static string GetTempPath(string filename = "")
@@ -824,6 +798,24 @@ namespace ServiceLib.Common
} }
} }
public static string GetBinConfigPath(string filename = "")
{
var tempPath = Path.Combine(StartupPath(), "binConfigs");
if (!Directory.Exists(tempPath))
{
Directory.CreateDirectory(tempPath);
}
if (Utils.IsNullOrEmpty(filename))
{
return tempPath;
}
else
{
return Path.Combine(tempPath, filename);
}
}
#endregion TempPath #endregion TempPath
#region Platform #region Platform
@@ -865,23 +857,25 @@ namespace ServiceLib.Common
private static async Task<string?> GetLinuxUserId() private static async Task<string?> GetLinuxUserId()
{ {
var arg = new List<string>() { "-c", "id -u" }; var arg = new List<string>() { "-c", "id -u" };
return await GetCliWrapOutput("/bin/bash", arg); return await GetCliWrapOutput(Global.LinuxBash, arg);
} }
public static async Task<string?> SetLinuxChmod(string? fileName) public static async Task<string?> SetLinuxChmod(string? fileName)
{ {
if (fileName.IsNullOrEmpty()) return null; if (fileName.IsNullOrEmpty())
if (fileName.Contains(' ')) fileName = fileName.AppendQuotes(); return null;
if (fileName.Contains(' '))
fileName = fileName.AppendQuotes();
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute); //File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
var arg = new List<string>() { "-c", $"chmod +x {fileName}" }; var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
return await GetCliWrapOutput("/bin/bash", arg); return await GetCliWrapOutput(Global.LinuxBash, arg);
} }
public static async Task<string?> GetLinuxFontFamily(string lang) public static async Task<string?> GetLinuxFontFamily(string lang)
{ {
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" }; // var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
var arg = new List<string>() { "-c", $"fc-list : family" }; var arg = new List<string>() { "-c", $"fc-list : family" };
return await GetCliWrapOutput("/bin/bash", arg); return await GetCliWrapOutput(Global.LinuxBash, arg);
} }
public static string? GetHomePath() public static string? GetHomePath()
@@ -891,12 +885,6 @@ namespace ServiceLib.Common
: Environment.GetEnvironmentVariable("HOME"); : Environment.GetEnvironmentVariable("HOME");
} }
public static async Task<string?> GetListNetworkServices()
{
var arg = new List<string>() { "-c", $"networksetup -listallnetworkservices" };
return await GetCliWrapOutput("/bin/bash", arg);
}
#endregion Platform #endregion Platform
} }
} }

View File

@@ -1,4 +1,6 @@
using Microsoft.Win32; using System.Security.Cryptography;
using System.Text;
using Microsoft.Win32;
namespace ServiceLib.Common namespace ServiceLib.Common
{ {
@@ -50,5 +52,23 @@ namespace ServiceLib.Common
regKey?.Close(); regKey?.Close();
} }
} }
public static async Task RemoveTunDevice()
{
try
{
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
var guid = new Guid(sum);
var pnpUtilPath = @"C:\Windows\System32\pnputil.exe";
var arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
// Try to remove the device
await Utils.GetCliWrapOutput(pnpUtilPath, arg);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
} }
} }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Enums namespace ServiceLib.Enums
{ {
public enum ECoreType public enum ECoreType
{ {
@@ -12,6 +12,8 @@
sing_box = 24, sing_box = 24,
juicity = 25, juicity = 25,
hysteria2 = 26, hysteria2 = 26,
brook = 27,
overtls = 28,
v2rayN = 99 v2rayN = 99
} }
} }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Enums namespace ServiceLib.Enums
{ {
public enum EMsgCommand public enum EMsgCommand
{ {
@@ -6,7 +6,6 @@
SendMsgView, SendMsgView,
SendSnackMsg, SendSnackMsg,
RefreshProfiles, RefreshProfiles,
StopSpeedtest,
AppExit AppExit
} }
} }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib namespace ServiceLib
{ {
public class Global public class Global
{ {
@@ -7,18 +7,8 @@
public const string AppName = "v2rayN"; public const string AppName = "v2rayN";
public const string GithubUrl = "https://github.com"; public const string GithubUrl = "https://github.com";
public const string GithubApiUrl = "https://api.github.com/repos"; public const string GithubApiUrl = "https://api.github.com/repos";
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
public const string MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
public const string SingboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat"; public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204"; public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs"; public const string 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 IPAPIUrl = "https://api.ip.sb/geoip";
@@ -26,7 +16,7 @@
public const string ConfigFileName = "guiNConfig.json"; public const string ConfigFileName = "guiNConfig.json";
public const string CoreConfigFileName = "config.json"; public const string CoreConfigFileName = "config.json";
public const string CorePreConfigFileName = "configPre.json"; public const string CorePreConfigFileName = "configPre.json";
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json"; public const string CoreSpeedtestConfigFileName = "configTest{0}.json";
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json"; public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
public const string ClashMixinConfigFileName = "Mixin.yaml"; public const string ClashMixinConfigFileName = "Mixin.yaml";
@@ -48,6 +38,8 @@
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml"; public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config"; public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
public const string PacFileName = NamespaceSample + "pac"; public const string PacFileName = NamespaceSample + "pac";
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
public const string DefaultSecurity = "auto"; public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp"; public const string DefaultNetwork = "tcp";
@@ -68,83 +60,93 @@
public const string UserEMail = "t@t.tt"; public const string UserEMail = "t@t.tt";
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
public const string AutoRunName = "v2rayNAutoRun"; public const string AutoRunName = "v2rayNAutoRun";
public const string CustomIconName = "v2rayN.ico";
public const string SystemProxyExceptionsWindows = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*"; public const string SystemProxyExceptionsWindows = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
public const string SystemProxyExceptionsLinux = "localhost,127.0.0.0/8,::1"; public const string SystemProxyExceptionsLinux = "localhost,127.0.0.0/8,::1";
public const string RoutingRuleComma = "<COMMA>"; public const string RoutingRuleComma = "<COMMA>";
public const string GrpcGunMode = "gun"; public const string GrpcGunMode = "gun";
public const string GrpcMultiMode = "multi"; public const string GrpcMultiMode = "multi";
public const int MaxPort = 65536; public const int MaxPort = 65536;
public const string DelayUnit = "";
public const string SpeedUnit = "";
public const int MinFontSize = 8; public const int MinFontSize = 8;
public const string RebootAs = "rebootas"; public const string RebootAs = "rebootas";
public const string AvaAssets = "avares://v2rayN/Assets/"; public const string AvaAssets = "avares://v2rayN/Assets/";
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2";
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
public const int SpeedTestPageSize = 1000;
public const string LinuxBash = "/bin/bash";
public static readonly List<string> IEProxyProtocols = new() { public static readonly List<string> IEProxyProtocols =
[
"{ip}:{http_port}", "{ip}:{http_port}",
"socks={ip}:{socks_port}", "socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}", "http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}", "http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
"" ""
}; ];
public static readonly List<string> SubConvertUrls = new List<string> { public static readonly List<string> SubConvertUrls =
[
@"https://sub.xeton.dev/sub?url={0}", @"https://sub.xeton.dev/sub?url={0}",
@"https://api.dler.io/sub?url={0}", @"https://api.dler.io/sub?url={0}",
@"http://127.0.0.1:25500/sub?url={0}", @"http://127.0.0.1:25500/sub?url={0}",
"" ""
}; ];
public static readonly List<string> SubConvertConfig = new List<string> { public static readonly List<string> SubConvertConfig =
@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini" [@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"];
};
public static readonly List<string> SubConvertTargets = new List<string> { public static readonly List<string> SubConvertTargets =
[
"", "",
"mixed", "mixed",
"v2ray", "v2ray",
"clash", "clash",
"ss", "ss"
}; ];
public static readonly List<string> SpeedTestUrls = new() { public static readonly List<string> SpeedTestUrls =
@"https://speed.cloudflare.com/__down?bytes=100000000", [
@"https://speed.cloudflare.com/__down?bytes=50000000",
@"https://speed.cloudflare.com/__down?bytes=10000000",
@"https://cachefly.cachefly.net/50mb.test", @"https://cachefly.cachefly.net/50mb.test",
}; @"https://speed.cloudflare.com/__down?bytes=10000000",
@"https://speed.cloudflare.com/__down?bytes=50000000",
@"https://speed.cloudflare.com/__down?bytes=100000000",
];
public static readonly List<string> SpeedPingTestUrls = new() { public static readonly List<string> SpeedPingTestUrls =
[
@"https://www.google.com/generate_204", @"https://www.google.com/generate_204",
@"https://www.gstatic.com/generate_204", @"https://www.gstatic.com/generate_204",
@"https://www.apple.com/library/test/success.html", @"https://www.apple.com/library/test/success.html",
@"http://www.msftconnecttest.com/connecttest.txt", @"http://www.msftconnecttest.com/connecttest.txt"
}; ];
public static readonly List<string> GeoFilesSources = new() { public static readonly List<string> GeoFilesSources =
[
"", "",
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat", @"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat", @"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat"
}; ];
public static readonly List<string> SingboxRulesetSources = new() { public static readonly List<string> SingboxRulesetSources =
[
"", "",
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs", @"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs", @"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs"
}; ];
public static readonly List<string> RoutingRulesSources = new() { public static readonly List<string> RoutingRulesSources =
[
"", "",
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json", @"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json", @"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json"
}; ];
public static readonly List<string> DNSTemplateSources = new() { public static readonly List<string> DNSTemplateSources =
[
"", "",
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/", @"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/", @"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/"
}; ];
public static readonly Dictionary<string, string> UserAgentTexts = new() public static readonly Dictionary<string, string> UserAgentTexts = new()
{ {
@@ -159,65 +161,361 @@
public static readonly Dictionary<EConfigType, string> ProtocolShares = new() public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
{ {
{EConfigType.VMess,"vmess://"}, { EConfigType.VMess, "vmess://" },
{EConfigType.Shadowsocks,"ss://"}, { EConfigType.Shadowsocks, "ss://" },
{EConfigType.SOCKS,"socks://"}, { EConfigType.SOCKS, "socks://" },
{EConfigType.VLESS,"vless://"}, { EConfigType.VLESS, "vless://" },
{EConfigType.Trojan,"trojan://"}, { EConfigType.Trojan, "trojan://" },
{EConfigType.Hysteria2,"hysteria2://"}, { EConfigType.Hysteria2, "hysteria2://" },
{EConfigType.TUIC,"tuic://"}, { EConfigType.TUIC, "tuic://" },
{EConfigType.WireGuard,"wireguard://"} { EConfigType.WireGuard, "wireguard://" }
}; };
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new() public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
{ {
{EConfigType.VMess,"vmess"}, { EConfigType.VMess, "vmess" },
{EConfigType.Shadowsocks,"shadowsocks"}, { EConfigType.Shadowsocks, "shadowsocks" },
{EConfigType.SOCKS,"socks"}, { EConfigType.SOCKS, "socks" },
{EConfigType.HTTP,"http"}, { EConfigType.HTTP, "http" },
{EConfigType.VLESS,"vless"}, { EConfigType.VLESS, "vless" },
{EConfigType.Trojan,"trojan"}, { EConfigType.Trojan, "trojan" },
{EConfigType.Hysteria2,"hysteria2"}, { EConfigType.Hysteria2, "hysteria2" },
{EConfigType.TUIC,"tuic"}, { EConfigType.TUIC, "tuic" },
{EConfigType.WireGuard,"wireguard"} { EConfigType.WireGuard, "wireguard" }
}; };
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" }; public static readonly List<string> VmessSecurities =
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> 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" }; "aes-128-gcm",
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" }; "chacha20-poly1305",
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" }; "auto",
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "xhttp", "h2", "quic", "grpc" }; "none",
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" }; "zero"
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> SsSecurities =
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" }; [
public static readonly List<string> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" }; "aes-256-gcm",
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"]; "aes-128-gcm",
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"]; "chacha20-poly1305",
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru", "hu" }; "chacha20-ietf-poly1305",
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" }; "none",
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" }; "plain"
public static readonly List<string> InboundTags = new() { "socks", "socks2", "socks3" }; ];
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
public static readonly List<string> TunStacks = new() { "gvisor", "system", "mixed" };
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
public static readonly List<string> allowSelectType = new() { "selector", "urltest", "loadbalance", "fallback" }; public static readonly List<string> SsSecuritiesInXray =
public static readonly List<string> notAllowTestType = new() { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" }; [
public static readonly List<string> proxyVehicleType = new() { "file", "http" }; "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 =
[
"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 =
[
"",
"xtls-rprx-vision",
"xtls-rprx-vision-udp443"
];
public static readonly List<string> Networks =
[
"tcp",
"kcp",
"ws",
"httpupgrade",
"xhttp",
"h2",
"quic",
"grpc"
];
public static readonly List<string> KcpHeaderTypes =
[
"srtp",
"utp",
"wechat-video",
"dtls",
"wireguard"
];
public static readonly List<string> CoreTypes =
[
"Xray",
"sing_box"
];
public static readonly List<string> DomainStrategies =
[
"AsIs",
"IPIfNonMatch",
"IPOnDemand"
];
public static readonly List<string> DomainStrategies4Singbox =
[
"ipv4_only",
"ipv6_only",
"prefer_ipv4",
"prefer_ipv6",
""
];
public static readonly List<string> DomainMatchers =
[
"linear",
"mph",
""
];
public static readonly List<string> Fingerprints =
[
"chrome",
"firefox",
"safari",
"ios",
"android",
"edge",
"360",
"qq",
"random",
"randomized",
""
];
public static readonly List<string> UserAgent =
[
"chrome",
"firefox",
"safari",
"edge",
"none"
];
public static readonly List<string> XhttpMode =
[
"auto",
"packet-up",
"stream-up",
"stream-one"
];
public static readonly List<string> AllowInsecure =
[
"true",
"false",
""
];
public static readonly List<string> DomainStrategy4Freedoms =
[
"AsIs",
"UseIP",
"UseIPv4",
"UseIPv6",
""
];
public static readonly List<string> SingboxDomainStrategy4Out =
[
"ipv4_only",
"prefer_ipv4",
"prefer_ipv6",
"ipv6_only",
""
];
public static readonly List<string> DomainDNSAddress =
[
"223.5.5.5",
"223.6.6.6",
"localhost"
];
public static readonly List<string> SingboxDomainDNSAddress =
[
"223.5.5.5",
"223.6.6.6",
"dhcp://auto"
];
public static readonly List<string> Languages =
[
"zh-Hans",
"zh-Hant",
"en",
"fa-Ir",
"ru",
"hu"
];
public static readonly List<string> Alpns =
[
"h3",
"h2",
"http/1.1",
"h3,h2",
"h2,http/1.1",
"h3,h2,http/1.1",
""
];
public static readonly List<string> LogLevels =
[
"debug",
"info",
"warning",
"error",
"none"
];
public static readonly List<string> InboundTags =
[
"socks",
"socks2",
"socks3"
];
public static readonly List<string> RuleProtocols =
[
"http",
"tls",
"bittorrent"
];
public static readonly List<string> RuleNetworks =
[
"",
"tcp",
"udp",
"tcp,udp"
];
public static readonly List<string> destOverrideProtocols =
[
"http",
"tls",
"quic",
"fakedns",
"fakedns+others"
];
public static readonly List<int> TunMtus =
[
1280,
1408,
1500,
9000
];
public static readonly List<string> TunStacks =
[
"gvisor",
"system",
"mixed"
];
public static readonly List<string> PresetMsgFilters =
[
"proxy",
"direct",
"block",
""
];
public static readonly List<string> SingboxMuxs =
[
"h2mux",
"smux",
"yamux",
""
];
public static readonly List<string> TuicCongestionControls =
[
"cubic",
"new_reno",
"bbr"
];
public static readonly List<string> allowSelectType =
[
"selector",
"urltest",
"loadbalance",
"fallback"
];
public static readonly List<string> notAllowTestType =
[
"selector",
"urltest",
"direct",
"reject",
"compatible",
"pass",
"loadbalance",
"fallback"
];
public static readonly List<string> proxyVehicleType =
[
"file",
"http"
];
public static readonly Dictionary<ECoreType, string> CoreUrls = new()
{
{ ECoreType.v2fly, "v2fly/v2ray-core" },
{ ECoreType.v2fly_v5, "v2fly/v2ray-core" },
{ ECoreType.Xray, "XTLS/Xray-core" },
{ ECoreType.sing_box, "SagerNet/sing-box" },
{ ECoreType.mihomo, "MetaCubeX/mihomo" },
{ ECoreType.hysteria, "apernet/hysteria" },
{ ECoreType.hysteria2, "apernet/hysteria" },
{ ECoreType.naiveproxy, "klzgrad/naiveproxy" },
{ ECoreType.tuic, "EAimTY/tuic" },
{ ECoreType.juicity, "juicity/juicity" },
{ ECoreType.brook, "txthinking/brook" },
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" },
{ ECoreType.v2rayN, "2dust/v2rayN" },
};
public static readonly List<string> OtherGeoUrls =
[
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat",
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb",
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
];
#endregion const #endregion const
} }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler namespace ServiceLib.Handler
{ {
public sealed class AppHandler public sealed class AppHandler
{ {
@@ -46,9 +46,9 @@
public bool InitApp() public bool InitApp()
{ {
if (Utils.IsNonWindows() && Utils.HasWritePermission() == false) if (Utils.HasWritePermission() == false)
{ {
Environment.SetEnvironmentVariable("V2RAYN_LOCAL_APPLICATION_DATA", "1", EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable(Global.LocalAppData, "1", EnvironmentVariableTarget.Process);
} }
Logging.Setup(); Logging.Setup();
@@ -98,6 +98,7 @@
{ {
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1)); FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1)); FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
}); });
} }

View File

@@ -1,4 +1,4 @@
using System.Security.Principal; using System.Security.Principal;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace ServiceLib.Handler namespace ServiceLib.Handler
@@ -29,7 +29,12 @@ namespace ServiceLib.Handler
} }
else if (Utils.IsOSX()) else if (Utils.IsOSX())
{ {
//TODO await ClearTaskOSX();
if (config.GuiItem.AutoRun)
{
await SetTaskOSX();
}
} }
return true; return true;
@@ -137,7 +142,7 @@ namespace ServiceLib.Handler
{ {
try try
{ {
var linuxConfig = Utils.GetEmbedText(Global.LinuxAutostartConfig); var linuxConfig = EmbedUtils.GetEmbedText(Global.LinuxAutostartConfig);
if (linuxConfig.IsNotEmpty()) if (linuxConfig.IsNotEmpty())
{ {
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath()); linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
@@ -161,5 +166,77 @@ namespace ServiceLib.Handler
} }
#endregion Linux #endregion Linux
#region macOS
private static async Task ClearTaskOSX()
{
try
{
var launchAgentPath = GetLaunchAgentPathMacOS();
if (File.Exists(launchAgentPath))
{
var args = new[] { "-c", $"launchctl unload -w \"{launchAgentPath}\"" };
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
File.Delete(launchAgentPath);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
private static async Task SetTaskOSX()
{
try
{
var plistContent = GenerateLaunchAgentPlist();
var launchAgentPath = GetLaunchAgentPathMacOS();
await File.WriteAllTextAsync(launchAgentPath, plistContent);
var args = new[] { "-c", $"launchctl load -w \"{launchAgentPath}\"" };
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
private static string GetLaunchAgentPathMacOS()
{
var homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var launchAgentPath = Path.Combine(homePath, "Library", "LaunchAgents", $"{Global.AppName}-LaunchAgent.plist");
Directory.CreateDirectory(Path.GetDirectoryName(launchAgentPath));
return launchAgentPath;
}
private static string GenerateLaunchAgentPlist()
{
var exePath = Utils.GetExePath();
var appName = Path.GetFileNameWithoutExtension(exePath);
return $@"<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version=""1.0"">
<dict>
<key>Label</key>
<string>{Global.AppName}-LaunchAgent</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
<string>if ! pgrep -x ""{appName}"" > /dev/null; then ""{exePath}""; fi</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
</dict>
</plist>";
}
#endregion macOS
} }
} }

View File

@@ -1,4 +1,4 @@
using static ServiceLib.Models.ClashProxies; using static ServiceLib.Models.ClashProxies;
namespace ServiceLib.Handler namespace ServiceLib.Handler
{ {
@@ -41,7 +41,7 @@ namespace ServiceLib.Handler
{ {
if (blAll) if (blAll)
{ {
for (int i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
{ {
if (_proxies != null) if (_proxies != null)
{ {
@@ -75,7 +75,7 @@ namespace ServiceLib.Handler
var urlBase = $"{GetApiUrl()}/proxies"; var urlBase = $"{GetApiUrl()}/proxies";
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl; urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
List<Task> tasks = new List<Task>(); var tasks = new List<Task>();
foreach (var it in lstProxy) foreach (var it in lstProxy)
{ {
if (Global.notAllowTestType.Contains(it.Type.ToLower())) if (Global.notAllowTestType.Contains(it.Type.ToLower()))
@@ -120,7 +120,7 @@ namespace ServiceLib.Handler
try try
{ {
var url = $"{GetApiUrl()}/proxies/{name}"; var url = $"{GetApiUrl()}/proxies/{name}";
Dictionary<string, string> headers = new Dictionary<string, string>(); var headers = new Dictionary<string, string>();
headers.Add("name", nameNode); headers.Add("name", nameNode);
await HttpClientHelper.Instance.PutAsync(url, headers); await HttpClientHelper.Instance.PutAsync(url, headers);
} }
@@ -148,7 +148,7 @@ namespace ServiceLib.Handler
try try
{ {
var url = $"{GetApiUrl()}/configs?force=true"; var url = $"{GetApiUrl()}/configs?force=true";
Dictionary<string, string> headers = new Dictionary<string, string>(); var headers = new Dictionary<string, string>();
headers.Add("path", filePath); headers.Add("path", filePath);
await HttpClientHelper.Instance.PutAsync(url, headers); await HttpClientHelper.Instance.PutAsync(url, headers);
} }

View File

@@ -21,7 +21,7 @@ namespace ServiceLib.Handler
public static Config? LoadConfig() public static Config? LoadConfig()
{ {
Config? config = null; Config? config = null;
var result = Utils.LoadResource(Utils.GetConfigPath(_configRes)); var result = EmbedUtils.LoadResource(Utils.GetConfigPath(_configRes));
if (Utils.IsNotEmpty(result)) if (Utils.IsNotEmpty(result))
{ {
config = JsonUtils.Deserialize<Config>(result); config = JsonUtils.Deserialize<Config>(result);
@@ -105,14 +105,9 @@ namespace ServiceLib.Handler
if (Utils.IsNullOrEmpty(config.UiItem.CurrentLanguage)) if (Utils.IsNullOrEmpty(config.UiItem.CurrentLanguage))
{ {
if (Thread.CurrentThread.CurrentCulture.Name.Equals("zh-cn", StringComparison.CurrentCultureIgnoreCase)) config.UiItem.CurrentLanguage = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.Equals("zh", StringComparison.CurrentCultureIgnoreCase)
{ ? Global.Languages.First()
config.UiItem.CurrentLanguage = Global.Languages.First(); : Global.Languages[2];
}
else
{
config.UiItem.CurrentLanguage = Global.Languages[2];
}
} }
config.ConstItem ??= new ConstItem(); config.ConstItem ??= new ConstItem();
@@ -130,6 +125,10 @@ namespace ServiceLib.Handler
{ {
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl; config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
} }
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
{
config.SpeedTestItem.MixedConcurrencyCount = 5;
}
config.Mux4RayItem ??= new() config.Mux4RayItem ??= new()
{ {
@@ -159,6 +158,7 @@ namespace ServiceLib.Handler
Length = "100-200", Length = "100-200",
Interval = "10-20" Interval = "10-20"
}; };
config.GlobalHotkeys ??= new();
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty()) if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
{ {
@@ -295,7 +295,7 @@ namespace ServiceLib.Handler
/// <param name="config"></param> /// <param name="config"></param>
/// <param name="indexes"></param> /// <param name="indexes"></param>
/// <returns></returns> /// <returns></returns>
public static async Task<int> RemoveServer(Config config, List<ProfileItem> indexes) public static async Task<int> RemoveServers(Config config, List<ProfileItem> indexes)
{ {
var subid = "TempRemoveSubId"; var subid = "TempRemoveSubId";
foreach (var item in indexes) foreach (var item in indexes)
@@ -304,7 +304,7 @@ namespace ServiceLib.Handler
} }
await SQLiteHelper.Instance.UpdateAllAsync(indexes); await SQLiteHelper.Instance.UpdateAllAsync(indexes);
await RemoveServerViaSubid(config, subid, false); await RemoveServersViaSubid(config, subid, false);
return 0; return 0;
} }
@@ -725,7 +725,7 @@ namespace ServiceLib.Handler
profileItem.Network = string.Empty; profileItem.Network = string.Empty;
if (profileItem.ShortId.IsNullOrEmpty()) if (profileItem.ShortId.IsNullOrEmpty())
{ {
profileItem.ShortId = Global.TunMtus.FirstOrDefault(); profileItem.ShortId = Global.TunMtus.First().ToString();
} }
if (profileItem.Id.IsNullOrEmpty()) if (profileItem.Id.IsNullOrEmpty())
@@ -759,9 +759,9 @@ namespace ServiceLib.Handler
Security = t.Security, Security = t.Security,
Network = t.Network, Network = t.Network,
StreamSecurity = t.StreamSecurity, StreamSecurity = t.StreamSecurity,
Delay = t33 == null ? 0 : t33.Delay, Delay = t33?.Delay ?? 0,
Speed = t33 == null ? 0 : t33.Speed, Speed = t33?.Speed ?? 0,
Sort = t33 == null ? 0 : t33.Sort Sort = t33?.Sort ?? 0
}).ToList(); }).ToList();
Enum.TryParse(colName, true, out EServerColName name); Enum.TryParse(colName, true, out EServerColName name);
@@ -873,7 +873,8 @@ namespace ServiceLib.Handler
List<ProfileItem> lstKeep = new(); List<ProfileItem> lstKeep = new();
List<ProfileItem> lstRemove = new(); List<ProfileItem> lstRemove = new();
if (!config.GuiItem.KeepOlderDedupl) lstProfile.Reverse(); if (!config.GuiItem.KeepOlderDedupl)
lstProfile.Reverse();
foreach (ProfileItem item in lstProfile) foreach (ProfileItem item in lstProfile)
{ {
@@ -886,7 +887,7 @@ namespace ServiceLib.Handler
lstRemove.Add(item); lstRemove.Add(item);
} }
} }
await RemoveServer(config, lstRemove); await RemoveServers(config, lstRemove);
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count); return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
} }
@@ -1051,6 +1052,24 @@ namespace ServiceLib.Handler
return itemSocks; return itemSocks;
} }
public static async Task<int> RemoveInvalidServerResult(Config config, string subid)
{
var lstModel = await AppHandler.Instance.ProfileItems(subid, "");
if (lstModel is { Count: <= 0 })
{
return -1;
}
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
var lstProfile = (from t in lstModel
join t2 in lstProfileExs on t.IndexId equals t2.IndexId
where t2.Delay == -1
select t).ToList();
await RemoveServers(config, JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstProfile)));
return lstProfile.Count;
}
#endregion Server #endregion Server
#region Batch add servers #region Batch add servers
@@ -1073,7 +1092,7 @@ namespace ServiceLib.Handler
//remove sub items //remove sub items
if (isSub && Utils.IsNotEmpty(subid)) if (isSub && Utils.IsNotEmpty(subid))
{ {
await RemoveServerViaSubid(config, subid, isSub); await RemoveServersViaSubid(config, subid, isSub);
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? ""; subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
} }
@@ -1167,7 +1186,7 @@ namespace ServiceLib.Handler
{ {
if (isSub && Utils.IsNotEmpty(subid)) if (isSub && Utils.IsNotEmpty(subid))
{ {
await RemoveServerViaSubid(config, subid, isSub); await RemoveServersViaSubid(config, subid, isSub);
} }
int count = 0; int count = 0;
foreach (var it in lstProfiles) foreach (var it in lstProfiles)
@@ -1223,7 +1242,7 @@ namespace ServiceLib.Handler
if (isSub && Utils.IsNotEmpty(subid)) if (isSub && Utils.IsNotEmpty(subid))
{ {
await RemoveServerViaSubid(config, subid, isSub); await RemoveServersViaSubid(config, subid, isSub);
} }
profileItem.Subid = subid; profileItem.Subid = subid;
@@ -1248,7 +1267,7 @@ namespace ServiceLib.Handler
if (isSub && Utils.IsNotEmpty(subid)) if (isSub && Utils.IsNotEmpty(subid))
{ {
await RemoveServerViaSubid(config, subid, isSub); await RemoveServersViaSubid(config, subid, isSub);
} }
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData); var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
@@ -1363,7 +1382,8 @@ namespace ServiceLib.Handler
}; };
var uri = Utils.TryUri(url); var uri = Utils.TryUri(url);
if (uri == null) return -1; if (uri == null)
return -1;
//Do not allow http protocol //Do not allow http protocol
if (url.StartsWith(Global.HttpProtocol) && !Utils.IsPrivateNetwork(uri.IdnHost)) if (url.StartsWith(Global.HttpProtocol) && !Utils.IsPrivateNetwork(uri.IdnHost))
{ {
@@ -1434,7 +1454,7 @@ namespace ServiceLib.Handler
/// <param name="config"></param> /// <param name="config"></param>
/// <param name="subid"></param> /// <param name="subid"></param>
/// <returns></returns> /// <returns></returns>
public static async Task<int> RemoveServerViaSubid(Config config, string subid, bool isSub) public static async Task<int> RemoveServersViaSubid(Config config, string subid, bool isSub)
{ {
if (Utils.IsNullOrEmpty(subid)) if (Utils.IsNullOrEmpty(subid))
{ {
@@ -1465,7 +1485,7 @@ namespace ServiceLib.Handler
return 0; return 0;
} }
await SQLiteHelper.Instance.DeleteAsync(item); await SQLiteHelper.Instance.DeleteAsync(item);
await RemoveServerViaSubid(config, id, false); await RemoveServersViaSubid(config, id, false);
return 0; return 0;
} }
@@ -1733,7 +1753,7 @@ namespace ServiceLib.Handler
Url = string.Empty, Url = string.Empty,
Sort = maxSort + 1, Sort = maxSort + 1,
}; };
await AddBatchRoutingRules(item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white")); await AddBatchRoutingRules(item2, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "white"));
//Blacklist //Blacklist
var item3 = new RoutingItem() var item3 = new RoutingItem()
@@ -1742,7 +1762,7 @@ namespace ServiceLib.Handler
Url = string.Empty, Url = string.Empty,
Sort = maxSort + 2, Sort = maxSort + 2,
}; };
await AddBatchRoutingRules(item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black")); await AddBatchRoutingRules(item3, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "black"));
//Global //Global
var item1 = new RoutingItem() var item1 = new RoutingItem()
@@ -1751,7 +1771,7 @@ namespace ServiceLib.Handler
Url = string.Empty, Url = string.Empty,
Sort = maxSort + 3, Sort = maxSort + 3,
}; };
await AddBatchRoutingRules(item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global")); await AddBatchRoutingRules(item1, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "global"));
if (!blImportAdvancedRules) if (!blImportAdvancedRules)
{ {

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler namespace ServiceLib.Handler
{ {
/// <summary> /// <summary>
/// Core configuration file processing class /// Core configuration file processing class
@@ -109,6 +109,30 @@
return result; return result;
} }
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, ProfileItem node, ServerTestItem testItem, string fileName)
{
var result = new RetResult();
var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
var port = Utils.GetFreePort(initPort + testItem.QueueNum);
testItem.Port = port;
if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
{
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(node, port);
}
else
{
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(node, port);
}
if (result.Success != true)
{
return result;
}
await File.WriteAllTextAsync(fileName, result.Data.ToString());
return result;
}
public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType) public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType)
{ {
var result = new RetResult(); var result = new RetResult();

View File

@@ -1,4 +1,4 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
namespace ServiceLib.Handler namespace ServiceLib.Handler
@@ -22,8 +22,19 @@ namespace ServiceLib.Handler
_config = config; _config = config;
_updateFunc = updateFunc; _updateFunc = updateFunc;
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
//Copy the bin folder to the storage location (for init)
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
{
var fromPath = Utils.GetBaseDirectory("bin");
var toPath = Utils.GetBinPath("");
if (fromPath != toPath)
{
FileManager.CopyDirectory(fromPath, toPath, true, false);
}
}
if (Utils.IsNonWindows()) if (Utils.IsNonWindows())
{ {
@@ -59,7 +70,7 @@ namespace ServiceLib.Handler
return; return;
} }
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName); var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName); var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
if (result.Success != true) if (result.Success != true)
{ {
@@ -72,6 +83,13 @@ namespace ServiceLib.Handler
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))); UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop(); await CoreStop();
await Task.Delay(100); await Task.Delay(100);
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
{
await Task.Delay(100);
await WindowsUtils.RemoveTunDevice();
}
await CoreStart(node); await CoreStart(node);
await CoreStartPreService(node); await CoreStartPreService(node);
if (_process != null) if (_process != null)
@@ -83,7 +101,8 @@ namespace ServiceLib.Handler
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds) public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
{ {
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray; var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName); var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType); var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
UpdateFunc(false, result.Msg); UpdateFunc(false, result.Msg);
if (result.Success != true) if (result.Success != true)
@@ -95,7 +114,34 @@ namespace ServiceLib.Handler
UpdateFunc(false, configPath); UpdateFunc(false, configPath);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false); var proc = await RunProcess(coreInfo, fileName, true, false);
if (proc is null)
{
return -1;
}
return proc.Id;
}
public async Task<int> LoadCoreConfigSpeedtest(ServerTestItem testItem)
{
var node = await AppHandler.Instance.GetProfileItem(testItem.IndexId);
if (node is null)
{
return -1;
}
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, node, testItem, configPath);
if (result.Success != true)
{
return -1;
}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(coreInfo, fileName, true, false);
if (proc is null) if (proc is null)
{ {
return -1; return -1;
@@ -157,7 +203,7 @@ namespace ServiceLib.Handler
if (itemSocks != null) if (itemSocks != null)
{ {
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box; var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
var fileName = Utils.GetConfigPath(Global.CorePreConfigFileName); var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName); var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
if (result.Success) if (result.Success)
{ {
@@ -207,8 +253,8 @@ namespace ServiceLib.Handler
StartInfo = new() StartInfo = new()
{ {
FileName = fileName, FileName = fileName,
Arguments = string.Format(coreInfo.Arguments, configPath), Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
WorkingDirectory = Utils.GetConfigPath(), WorkingDirectory = Utils.GetBinConfigPath(),
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = displayLog, RedirectStandardOutput = displayLog,
RedirectStandardError = displayLog, RedirectStandardError = displayLog,
@@ -228,12 +274,14 @@ namespace ServiceLib.Handler
{ {
proc.OutputDataReceived += (sender, e) => proc.OutputDataReceived += (sender, e) =>
{ {
if (Utils.IsNullOrEmpty(e.Data)) return; if (Utils.IsNullOrEmpty(e.Data))
return;
UpdateFunc(false, e.Data + Environment.NewLine); UpdateFunc(false, e.Data + Environment.NewLine);
}; };
proc.ErrorDataReceived += (sender, e) => proc.ErrorDataReceived += (sender, e) =>
{ {
if (Utils.IsNullOrEmpty(e.Data)) return; if (Utils.IsNullOrEmpty(e.Data))
return;
UpdateFunc(false, e.Data + Environment.NewLine); UpdateFunc(false, e.Data + Environment.NewLine);
}; };
} }
@@ -247,7 +295,8 @@ namespace ServiceLib.Handler
await Task.Delay(10); await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd); await proc.StandardInput.WriteLineAsync(pwd);
} }
if (isNeedSudo) _linuxSudoPid = proc.Id; if (isNeedSudo)
_linuxSudoPid = proc.Id;
if (displayLog) if (displayLog)
{ {
@@ -266,7 +315,7 @@ namespace ServiceLib.Handler
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(_tag, ex); Logging.SaveLog(_tag, ex);
UpdateFunc(true, ex.Message); UpdateFunc(mayNeedSudo, ex.Message);
return null; return null;
} }
} }
@@ -277,7 +326,7 @@ namespace ServiceLib.Handler
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath) 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 cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh"); var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
proc.StartInfo.FileName = shFilePath; proc.StartInfo.FileName = shFilePath;
@@ -331,7 +380,7 @@ namespace ServiceLib.Handler
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName) private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
{ {
//Shell scripts //Shell scripts
var shFilePath = Utils.GetBinPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName); var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
File.Delete(shFilePath); File.Delete(shFilePath);
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh"); sb.AppendLine("#!/bin/sh");

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler namespace ServiceLib.Handler
{ {
public sealed class CoreInfoHandler public sealed class CoreInfoHandler
{ {
@@ -44,7 +44,7 @@
} }
if (fileName.IsNullOrEmpty()) if (fileName.IsNullOrEmpty())
{ {
msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url); msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo?.CoreType.ToString()), coreInfo?.CoreExes?.LastOrDefault(), coreInfo?.Url);
Logging.SaveLog(msg); Logging.SaveLog(msg);
} }
return fileName; return fileName;
@@ -52,107 +52,102 @@
private void InitCoreInfo() private void InitCoreInfo()
{ {
var urlN = GetCoreUrl(ECoreType.v2rayN);
var urlXray = GetCoreUrl(ECoreType.Xray);
var urlMihomo = GetCoreUrl(ECoreType.mihomo);
var urlSingbox = GetCoreUrl(ECoreType.sing_box);
_coreInfo = _coreInfo =
[ [
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.v2rayN, CoreType = ECoreType.v2rayN,
Url = Global.NUrl, Url = GetCoreUrl(ECoreType.v2rayN),
ReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = urlN.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.NUrl + "/download/{0}/v2rayN-windows-64.zip", DownloadUrlWin64 = urlN + "/download/{0}/v2rayN-windows-64.zip",
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip", DownloadUrlWinArm64 = urlN + "/download/{0}/v2rayN-windows-arm64.zip",
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip", DownloadUrlLinux64 = urlN + "/download/{0}/v2rayN-linux-64.zip",
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip", DownloadUrlLinuxArm64 = urlN + "/download/{0}/v2rayN-linux-arm64.zip",
DownloadUrlOSX64 = Global.NUrl + "/download/{0}/v2rayN-macos-64.zip", DownloadUrlOSX64 = urlN + "/download/{0}/v2rayN-macos-64.zip",
DownloadUrlOSXArm64 = Global.NUrl + "/download/{0}/v2rayN-macos-arm64.zip", DownloadUrlOSXArm64 = urlN + "/download/{0}/v2rayN-macos-arm64.zip",
}, },
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.v2fly, CoreType = ECoreType.v2fly,
CoreExes = ["wv2ray", "v2ray"], CoreExes = ["v2ray"],
Arguments = "", Arguments = "{0}",
Url = Global.V2flyCoreUrl, Url = GetCoreUrl(ECoreType.v2fly),
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
Match = "V2Ray", Match = "V2Ray",
VersionArg = "-version", VersionArg = "-version",
RedirectInfo = true,
}, },
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.v2fly_v5, CoreType = ECoreType.v2fly_v5,
CoreExes = ["v2ray"], CoreExes = ["v2ray"],
Arguments = "run -c config.json -format jsonv5", Arguments = "run -c {0} -format jsonv5",
Url = Global.V2flyCoreUrl, Url = GetCoreUrl(ECoreType.v2fly_v5),
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
Match = "V2Ray", Match = "V2Ray",
VersionArg = "version", VersionArg = "version",
RedirectInfo = true,
}, },
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.Xray, CoreType = ECoreType.Xray,
CoreExes = ["xray", "wxray"], CoreExes = ["xray"],
Arguments = "run -c {0}", Arguments = "run -c {0}",
Url = Global.XrayCoreUrl, Url = GetCoreUrl(ECoreType.Xray),
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = urlXray.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip", DownloadUrlWin64 = urlXray + "/download/{0}/Xray-windows-64.zip",
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip", DownloadUrlWinArm64 = urlXray + "/download/{0}/Xray-windows-arm64-v8a.zip",
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip", DownloadUrlLinux64 = urlXray + "/download/{0}/Xray-linux-64.zip",
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip", DownloadUrlLinuxArm64 = urlXray + "/download/{0}/Xray-linux-arm64-v8a.zip",
DownloadUrlOSX64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-64.zip", DownloadUrlOSX64 = urlXray + "/download/{0}/Xray-macos-64.zip",
DownloadUrlOSXArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-macos-arm64-v8a.zip", DownloadUrlOSXArm64 = urlXray + "/download/{0}/Xray-macos-arm64-v8a.zip",
Match = "Xray", Match = "Xray",
VersionArg = "-version", VersionArg = "-version",
RedirectInfo = true,
}, },
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.mihomo, CoreType = ECoreType.mihomo,
CoreExes = ["mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash"], CoreExes = ["mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "clash", "mihomo"],
Arguments = "-f config.json" + PortableMode(), Arguments = "-f {0}" + PortableMode(),
Url = Global.MihomoCoreUrl, Url = GetCoreUrl(ECoreType.mihomo),
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = urlMihomo.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip", DownloadUrlWin64 = urlMihomo + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip", DownloadUrlWinArm64 = urlMihomo + "/download/{0}/mihomo-windows-arm64-{0}.zip",
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz", DownloadUrlLinux64 = urlMihomo + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz", DownloadUrlLinuxArm64 = urlMihomo + "/download/{0}/mihomo-linux-arm64-{0}.gz",
DownloadUrlOSX64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz", DownloadUrlOSX64 = urlMihomo + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz",
DownloadUrlOSXArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-darwin-arm64-{0}.gz", DownloadUrlOSXArm64 = urlMihomo + "/download/{0}/mihomo-darwin-arm64-{0}.gz",
Match = "Mihomo", Match = "Mihomo",
VersionArg = "-v", VersionArg = "-v",
RedirectInfo = true,
}, },
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.hysteria, CoreType = ECoreType.hysteria,
CoreExes = ["hysteria-windows-amd64", "hysteria"], CoreExes = ["hysteria"],
Arguments = "", Arguments = "",
Url = Global.HysteriaCoreUrl, Url = GetCoreUrl(ECoreType.hysteria),
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
RedirectInfo = true,
}, },
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.naiveproxy, CoreType = ECoreType.naiveproxy,
CoreExes = ["naiveproxy", "naive"], CoreExes = [ "naive", "naiveproxy"],
Arguments = "config.json", Arguments = "{0}",
Url = Global.NaiveproxyCoreUrl, Url = GetCoreUrl(ECoreType.naiveproxy),
RedirectInfo = false,
}, },
new CoreInfo new CoreInfo
{ {
CoreType = ECoreType.tuic, CoreType = ECoreType.tuic,
CoreExes = ["tuic-client", "tuic"], CoreExes = ["tuic-client", "tuic"],
Arguments = "-c config.json", Arguments = "-c {0}",
Url = Global.TuicCoreUrl, Url = GetCoreUrl(ECoreType.tuic),
RedirectInfo = true,
}, },
new CoreInfo new CoreInfo
@@ -160,15 +155,15 @@
CoreType = ECoreType.sing_box, CoreType = ECoreType.sing_box,
CoreExes = ["sing-box-client", "sing-box"], CoreExes = ["sing-box-client", "sing-box"],
Arguments = "run -c {0} --disable-color", Arguments = "run -c {0} --disable-color",
Url = Global.SingboxCoreUrl, Url = GetCoreUrl(ECoreType.sing_box),
RedirectInfo = true,
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = urlSingbox.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip", DownloadUrlWin64 = urlSingbox + "/download/{0}/sing-box-{1}-windows-amd64.zip",
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip", DownloadUrlWinArm64 = urlSingbox + "/download/{0}/sing-box-{1}-windows-arm64.zip",
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz", DownloadUrlLinux64 = urlSingbox + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz", DownloadUrlLinuxArm64 = urlSingbox + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
DownloadUrlOSX64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz", DownloadUrlOSX64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz",
DownloadUrlOSXArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz", DownloadUrlOSXArm64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz",
Match = "sing-box", Match = "sing-box",
VersionArg = "version", VersionArg = "version",
}, },
@@ -177,8 +172,8 @@
{ {
CoreType = ECoreType.juicity, CoreType = ECoreType.juicity,
CoreExes = ["juicity-client", "juicity"], CoreExes = ["juicity-client", "juicity"],
Arguments = "run -c config.json", Arguments = "run -c {0}",
Url = Global.JuicityCoreUrl Url = GetCoreUrl(ECoreType.juicity)
}, },
new CoreInfo new CoreInfo
@@ -186,17 +181,38 @@
CoreType = ECoreType.hysteria2, CoreType = ECoreType.hysteria2,
CoreExes = ["hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria"], CoreExes = ["hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria"],
Arguments = "", Arguments = "",
Url = Global.HysteriaCoreUrl, Url = GetCoreUrl(ECoreType.hysteria2),
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), },
RedirectInfo = true,
new CoreInfo
{
CoreType = ECoreType.brook,
CoreExes = ["brook_windows_amd64", "brook_linux_amd64", "brook"],
Arguments = " {0}",
Url = GetCoreUrl(ECoreType.brook),
AbsolutePath = true,
},
new CoreInfo
{
CoreType = ECoreType.overtls,
CoreExes = [ "overtls-bin", "overtls"],
Arguments = "-r client -c {0}",
Url = GetCoreUrl(ECoreType.overtls),
AbsolutePath = false,
} }
]; ];
} }
private string PortableMode() private static string PortableMode()
{ {
return $" -d {Utils.GetBinPath("").AppendQuotes()}"; return $" -d {Utils.GetBinPath("").AppendQuotes()}";
} }
private static string GetCoreUrl(ECoreType eCoreType)
{
return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases";
}
} }
} }

View File

@@ -1,4 +1,4 @@
using System.Collections.Specialized; using System.Collections.Specialized;
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
@@ -214,7 +214,8 @@ namespace ServiceLib.Handler.Fmt
{ {
foreach (var item in s) foreach (var item in s)
{ {
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true; if (str.Contains(item, StringComparison.OrdinalIgnoreCase))
return true;
} }
return false; return false;
} }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
public class Hysteria2Fmt : BaseFmt public class Hysteria2Fmt : BaseFmt
{ {
@@ -11,7 +11,8 @@
}; };
var url = Utils.TryUri(str); var url = Utils.TryUri(str);
if (url == null) return null; if (url == null)
return null;
item.Address = url.IdnHost; item.Address = url.IdnHost;
item.Port = url.Port; item.Port = url.Port;
@@ -28,7 +29,8 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
string url = string.Empty; string url = string.Empty;
string remark = string.Empty; string remark = string.Empty;

View File

@@ -1,4 +1,4 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
@@ -26,7 +26,8 @@ namespace ServiceLib.Handler.Fmt
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
string url = string.Empty; string url = string.Empty;
string remark = string.Empty; string remark = string.Empty;
@@ -82,7 +83,8 @@ namespace ServiceLib.Handler.Fmt
private static ProfileItem? ResolveSip002(string result) private static ProfileItem? ResolveSip002(string result)
{ {
var parsedUrl = Utils.TryUri(result); var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null) return null; if (parsedUrl == null)
return null;
ProfileItem item = new() ProfileItem item = new()
{ {

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
public class SocksFmt : BaseFmt public class SocksFmt : BaseFmt
{ {
@@ -23,7 +23,8 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
var url = string.Empty; var url = string.Empty;
var remark = string.Empty; var remark = string.Empty;
@@ -86,7 +87,8 @@
private static ProfileItem? ResolveSocksNew(string result) private static ProfileItem? ResolveSocksNew(string result)
{ {
var parsedUrl = Utils.TryUri(result); var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null) return null; if (parsedUrl == null)
return null;
ProfileItem item = new() ProfileItem item = new()
{ {

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
public class TrojanFmt : BaseFmt public class TrojanFmt : BaseFmt
{ {
@@ -12,7 +12,8 @@
}; };
var url = Utils.TryUri(str); var url = Utils.TryUri(str);
if (url == null) return null; if (url == null)
return null;
item.Address = url.IdnHost; item.Address = url.IdnHost;
item.Port = url.Port; item.Port = url.Port;
@@ -27,7 +28,8 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
string url = string.Empty; string url = string.Empty;
string remark = string.Empty; string remark = string.Empty;

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
public class TuicFmt : BaseFmt public class TuicFmt : BaseFmt
{ {
@@ -12,7 +12,8 @@
}; };
var url = Utils.TryUri(str); var url = Utils.TryUri(str);
if (url == null) return null; if (url == null)
return null;
item.Address = url.IdnHost; item.Address = url.IdnHost;
item.Port = url.Port; item.Port = url.Port;
@@ -34,7 +35,8 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
string url = string.Empty; string url = string.Empty;
string remark = string.Empty; string remark = string.Empty;

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
public class VLESSFmt : BaseFmt public class VLESSFmt : BaseFmt
{ {
@@ -13,7 +13,8 @@
}; };
var url = Utils.TryUri(str); var url = Utils.TryUri(str);
if (url == null) return null; if (url == null)
return null;
item.Address = url.IdnHost; item.Address = url.IdnHost;
item.Port = url.Port; item.Port = url.Port;
@@ -30,7 +31,8 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
string url = string.Empty; string url = string.Empty;
string remark = string.Empty; string remark = string.Empty;

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
public class VmessFmt : BaseFmt public class VmessFmt : BaseFmt
{ {
@@ -19,7 +19,8 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
string url = string.Empty; string url = string.Empty;
VmessQRCode vmessQRCode = new() VmessQRCode vmessQRCode = new()
@@ -106,7 +107,8 @@
}; };
var url = Utils.TryUri(str); var url = Utils.TryUri(str);
if (url == null) return null; if (url == null)
return null;
item.Address = url.IdnHost; item.Address = url.IdnHost;
item.Port = url.Port; item.Port = url.Port;

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt namespace ServiceLib.Handler.Fmt
{ {
public class WireguardFmt : BaseFmt public class WireguardFmt : BaseFmt
{ {
@@ -12,7 +12,8 @@
}; };
var url = Utils.TryUri(str); var url = Utils.TryUri(str);
if (url == null) return null; if (url == null)
return null;
item.Address = url.IdnHost; item.Address = url.IdnHost;
item.Port = url.Port; item.Port = url.Port;
@@ -31,7 +32,8 @@
public static string? ToUri(ProfileItem? item) public static string? ToUri(ProfileItem? item)
{ {
if (item == null) return null; if (item == null)
return null;
string url = string.Empty; string url = string.Empty;
string remark = string.Empty; string remark = string.Empty;

View File

@@ -1,4 +1,4 @@
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
namespace ServiceLib.Handler namespace ServiceLib.Handler
@@ -35,7 +35,7 @@ namespace ServiceLib.Handler
var path = Path.Combine(_configPath, "pac.txt"); var path = Path.Combine(_configPath, "pac.txt");
if (!File.Exists(path)) if (!File.Exists(path))
{ {
var pac = Utils.GetEmbedText(Global.PacFileName); var pac = EmbedUtils.GetEmbedText(Global.PacFileName);
await File.AppendAllTextAsync(path, pac); await File.AppendAllTextAsync(path, pac);
} }
@@ -89,7 +89,8 @@ namespace ServiceLib.Handler
public static void Stop() public static void Stop()
{ {
if (_tcpListener == null) return; if (_tcpListener == null)
return;
try try
{ {
_isRunning = false; _isRunning = false;

View File

@@ -1,4 +1,4 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
//using System.Reactive.Linq; //using System.Reactive.Linq;
@@ -8,7 +8,7 @@ namespace ServiceLib.Handler
{ {
private static readonly Lazy<ProfileExHandler> _instance = new(() => new()); private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx = []; private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
private Queue<string> _queIndexIds = new(); private readonly Queue<string> _queIndexIds = new();
public static ProfileExHandler Instance => _instance.Value; public static ProfileExHandler Instance => _instance.Value;
private static readonly string _tag = "ProfileExHandler"; private static readonly string _tag = "ProfileExHandler";
@@ -59,7 +59,7 @@ namespace ServiceLib.Handler
List<ProfileExItem> lstInserts = []; List<ProfileExItem> lstInserts = [];
List<ProfileExItem> lstUpdates = []; List<ProfileExItem> lstUpdates = [];
for (int i = 0; i < cnt; i++) for (var i = 0; i < cnt; i++)
{ {
var id = _queIndexIds.Dequeue(); var id = _queIndexIds.Dequeue();
var item = lstExists.FirstOrDefault(t => t.IndexId == id); var item = lstExists.FirstOrDefault(t => t.IndexId == id);
@@ -78,14 +78,19 @@ namespace ServiceLib.Handler
lstInserts.Add(itemNew); lstInserts.Add(itemNew);
} }
} }
try try
{ {
if (lstInserts.Count() > 0) if (lstInserts.Count > 0)
{
await SQLiteHelper.Instance.InsertAllAsync(lstInserts); await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
}
if (lstUpdates.Count() > 0) if (lstUpdates.Count > 0)
{
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates); await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
} }
}
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(_tag, ex); Logging.SaveLog(_tag, ex);
@@ -93,17 +98,24 @@ namespace ServiceLib.Handler
} }
} }
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx) private ProfileExItem AddProfileEx(string indexId)
{ {
profileEx = new() var profileEx = new ProfileExItem()
{ {
IndexId = indexId, IndexId = indexId,
Delay = 0, Delay = 0,
Speed = 0, Speed = 0,
Sort = 0 Sort = 0,
Message = string.Empty
}; };
_lstProfileEx.Add(profileEx); _lstProfileEx.Add(profileEx);
IndexIdEnqueue(indexId); IndexIdEnqueue(indexId);
return profileEx;
}
private ProfileExItem GetProfileExItem(string? indexId)
{
return _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId) ?? AddProfileEx(indexId);
} }
public async Task ClearAll() public async Task ClearAll()
@@ -124,39 +136,34 @@ namespace ServiceLib.Handler
} }
} }
public void SetTestDelay(string indexId, string delayVal) public void SetTestDelay(string indexId, int delay)
{ {
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId); var profileEx = GetProfileExItem(indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
int.TryParse(delayVal, out int delay);
profileEx.Delay = delay; profileEx.Delay = delay;
IndexIdEnqueue(indexId); IndexIdEnqueue(indexId);
} }
public void SetTestSpeed(string indexId, string speedVal) public void SetTestSpeed(string indexId, decimal speed)
{ {
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId); var profileEx = GetProfileExItem(indexId);
if (profileEx == null)
{ profileEx.Speed = speed;
AddProfileEx(indexId, ref profileEx); IndexIdEnqueue(indexId);
} }
decimal.TryParse(speedVal, out decimal speed); public void SetTestMessage(string indexId, string message)
profileEx.Speed = speed; {
var profileEx = GetProfileExItem(indexId);
profileEx.Message = message;
IndexIdEnqueue(indexId); IndexIdEnqueue(indexId);
} }
public void SetSort(string indexId, int sort) public void SetSort(string indexId, int sort)
{ {
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId); var profileEx = GetProfileExItem(indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
profileEx.Sort = sort; profileEx.Sort = sort;
IndexIdEnqueue(indexId); IndexIdEnqueue(indexId);
} }

View File

@@ -1,202 +1,33 @@
namespace ServiceLib.Handler.SysProxy namespace ServiceLib.Handler.SysProxy
{ {
public class ProxySettingLinux public class ProxySettingLinux
{ {
private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh";
public static async Task SetProxy(string host, int port, string exceptions) public static async Task SetProxy(string host, int port, string exceptions)
{ {
var lstCmd = GetSetCmds(host, port, exceptions); List<string> args = ["manual", host, port.ToString(), exceptions];
await ExecCmd(args);
await ExecCmd(lstCmd);
} }
public static async Task UnsetProxy() public static async Task UnsetProxy()
{ {
var lstCmd = GetUnsetCmds(); List<string> args = ["none"];
await ExecCmd(args);
await ExecCmd(lstCmd);
} }
private static async Task ExecCmd(List<CmdItem> lstCmd) private static async Task ExecCmd(List<string> args)
{ {
foreach (var cmd in lstCmd) var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{ {
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null) var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
{ await File.AppendAllTextAsync(fileName, contents);
continue;
} await Utils.SetLinuxChmod(fileName);
await Task.Delay(10);
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
}
} }
private static List<CmdItem> GetSetCmds(string host, int port, string exceptions) await Utils.GetCliWrapOutput(fileName, args);
{
var isKde = IsKde(out var configDir);
List<string> lstType = ["", "http", "https", "socks", "ftp"];
List<CmdItem> lstCmd = [];
//GNOME
foreach (var type in lstType)
{
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
}
if (exceptions.IsNotEmpty())
{
lstCmd.AddRange(GetSetCmd4Gnome("exceptions", exceptions, 0));
}
if (isKde)
{
foreach (var type in lstType)
{
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
}
if (exceptions.IsNotEmpty())
{
lstCmd.AddRange(GetSetCmd4Kde("exceptions", exceptions, 0, configDir));
}
// Notify system to reload
lstCmd.Add(new CmdItem()
{
Cmd = "dbus-send",
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
});
}
return lstCmd;
}
private static List<CmdItem> GetUnsetCmds()
{
var isKde = IsKde(out var configDir);
List<CmdItem> lstCmd = [];
//GNOME
lstCmd.Add(new CmdItem()
{
Cmd = "gsettings",
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
});
if (isKde)
{
lstCmd.Add(new CmdItem()
{
Cmd = GetKdeVersion(),
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
});
// Notify system to reload
lstCmd.Add(new CmdItem()
{
Cmd = "dbus-send",
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
});
}
return lstCmd;
}
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
{
List<CmdItem> lstCmd = [];
var cmd = GetKdeVersion();
if (type.IsNullOrEmpty())
{
lstCmd.Add(new()
{
Cmd = cmd,
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
});
}
else if (type == "exceptions")
{
lstCmd.Add(new()
{
Cmd = cmd,
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "NoProxyFor", host]
});
}
else
{
var type2 = type.Equals("https") ? "http" : type;
lstCmd.Add(new CmdItem()
{
Cmd = cmd,
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"]
});
}
return lstCmd;
}
private static List<CmdItem> GetSetCmd4Gnome(string type, string host, int port)
{
List<CmdItem> lstCmd = [];
if (type.IsNullOrEmpty())
{
lstCmd.Add(new()
{
Cmd = "gsettings",
Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"]
});
}
else if (type == "exceptions")
{
lstCmd.Add(new()
{
Cmd = "gsettings",
Arguments = ["set", $"org.gnome.system.proxy", "ignore-hosts", JsonUtils.Serialize(host.Split(','), false)]
});
}
else
{
lstCmd.Add(new()
{
Cmd = "gsettings",
Arguments = ["set", $"org.gnome.system.proxy.{type}", "host", host]
});
lstCmd.Add(new()
{
Cmd = "gsettings",
Arguments = ["set", $"org.gnome.system.proxy.{type}", "port", $"{port}"]
});
}
return lstCmd;
}
private static bool IsKde(out string configDir)
{
configDir = "/home";
var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
var desktop2 = Environment.GetEnvironmentVariable("XDG_SESSION_DESKTOP");
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase)
|| string.Equals(desktop, "plasma", StringComparison.OrdinalIgnoreCase)
|| string.Equals(desktop2, "KDE", StringComparison.OrdinalIgnoreCase)
|| string.Equals(desktop2, "plasma", StringComparison.OrdinalIgnoreCase);
if (isKde)
{
var homeDir = Environment.GetEnvironmentVariable("HOME");
if (homeDir != null)
{
configDir = Path.Combine(homeDir, ".config");
}
}
return isKde;
}
private static string GetKdeVersion()
{
var ver = Environment.GetEnvironmentVariable("KDE_SESSION_VERSION") ?? "0";
return ver switch
{
"6" => "kwriteconfig6",
_ => "kwriteconfig5"
};
} }
} }
} }

View File

@@ -1,101 +1,38 @@
namespace ServiceLib.Handler.SysProxy namespace ServiceLib.Handler.SysProxy
{ {
public class ProxySettingOSX public class ProxySettingOSX
{ {
/// <summary> private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh";
/// 应用接口类型
/// </summary>
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge", "USB 10/100/1000 LAN"];
/// <summary>
/// 代理类型,对应 http,https,socks
/// </summary>
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
public static async Task SetProxy(string host, int port, string exceptions) public static async Task SetProxy(string host, int port, string exceptions)
{ {
var lstInterface = await GetListNetworkServices(); List<string> args = ["set", host, port.ToString()];
var lstCmd = GetSetCmds(lstInterface, host, port, exceptions); if (exceptions.IsNotEmpty())
await ExecCmd(lstCmd); {
args.AddRange(exceptions.Split(','));
}
await ExecCmd(args);
} }
public static async Task UnsetProxy() public static async Task UnsetProxy()
{ {
var lstInterface = await GetListNetworkServices(); List<string> args = ["clear"];
var lstCmd = GetUnsetCmds(lstInterface); await ExecCmd(args);
await ExecCmd(lstCmd);
} }
private static async Task ExecCmd(List<CmdItem> lstCmd) private static async Task ExecCmd(List<string> args)
{ {
foreach (var cmd in lstCmd) var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{ {
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null) var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
{ await File.AppendAllTextAsync(fileName, contents);
continue;
await Utils.SetLinuxChmod(fileName);
} }
await Task.Delay(10); await Utils.GetCliWrapOutput(fileName, args);
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
}
}
private static List<CmdItem> GetSetCmds(List<string> lstInterface, string host, int port, string exceptions)
{
List<CmdItem> lstCmd = [];
foreach (var interf in lstInterface)
{
foreach (var type in LstTypes)
{
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = [$"-{type}", interf, host, port.ToString()]
});
}
if (exceptions.IsNotEmpty())
{
List<string> args = [$"-setproxybypassdomains", interf];
args.AddRange(exceptions.Split(','));
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = args
});
}
}
return lstCmd;
}
private static List<CmdItem> GetUnsetCmds(List<string> lstInterface)
{
List<CmdItem> lstCmd = [];
foreach (var interf in lstInterface)
{
foreach (var type in LstTypes)
{
lstCmd.Add(new CmdItem()
{
Cmd = "networksetup",
Arguments = [$"-{type}state", interf, "off"]
});
}
}
return lstCmd;
}
public static async Task<List<string>> GetListNetworkServices()
{
var services = await Utils.GetListNetworkServices();
if (services.IsNullOrEmpty())
{
return LstInterface;
}
var lst = services.Split(Environment.NewLine).Where(t => t.Length > 0 && t.Contains('*') == false);
return lst.ToList();
} }
} }
} }

View File

@@ -69,7 +69,7 @@ namespace ServiceLib.Handler.SysProxy
} }
return result; return result;
} }
catch (Exception ex) catch
{ {
SetProxyFallback(strProxy, exceptions, type); SetProxyFallback(strProxy, exceptions, type);
return false; return false;
@@ -176,7 +176,8 @@ namespace ServiceLib.Handler.SysProxy
} }
// FREE the data ASAP // FREE the data ASAP
if (list.szConnection != nint.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3 if (list.szConnection != nint.Zero)
Marshal.FreeHGlobal(list.szConnection); // release mem 3
if (optionCount > 1) if (optionCount > 1)
{ {
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1 Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1

View File

@@ -1,4 +1,4 @@
using System.Net; using System.Net;
using WebDav; using WebDav;
namespace ServiceLib.Handler namespace ServiceLib.Handler
@@ -61,7 +61,8 @@ namespace ServiceLib.Handler
private async Task<bool> TryCreateDir() private async Task<bool> TryCreateDir()
{ {
if (_client is null) return false; if (_client is null)
return false;
try try
{ {
var result2 = await _client.Mkcol(_webDir); var result2 = await _client.Mkcol(_webDir);

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class CoreBasicItem public class CoreBasicItem
@@ -156,7 +156,7 @@
public int SpeedTestTimeout { get; set; } public int SpeedTestTimeout { get; set; }
public string SpeedTestUrl { get; set; } public string SpeedTestUrl { get; set; }
public string SpeedPingTestUrl { get; set; } public string SpeedPingTestUrl { get; set; }
public int SpeedTestPageSize { get; set; } public int MixedConcurrencyCount { get; set; }
} }
[Serializable] [Serializable]

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class CoreInfo public class CoreInfo
@@ -16,6 +16,6 @@
public string? DownloadUrlOSXArm64 { get; set; } public string? DownloadUrlOSXArm64 { get; set; }
public string? Match { get; set; } public string? Match { get; set; }
public string? VersionArg { get; set; } public string? VersionArg { get; set; }
public bool RedirectInfo { get; set; } public bool AbsolutePath { get; set; }
} }
} }

View File

@@ -1,4 +1,4 @@
using SQLite; using SQLite;
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
@@ -11,5 +11,6 @@ namespace ServiceLib.Models
public int Delay { get; set; } public int Delay { get; set; }
public decimal Speed { get; set; } public decimal Speed { get; set; }
public int Sort { get; set; } public int Sort { get; set; }
public string? Message { get; set; }
} }
} }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
[Serializable] [Serializable]
public class ServerTestItem public class ServerTestItem
@@ -8,6 +8,6 @@
public int Port { get; set; } public int Port { get; set; }
public EConfigType ConfigType { get; set; } public EConfigType ConfigType { get; set; }
public bool AllowTest { get; set; } public bool AllowTest { get; set; }
public int Delay { get; set; } public int QueueNum { get; set; }
} }
} }

View File

@@ -4,23 +4,15 @@ namespace ServiceLib.Models
{ {
public class V2rayConfig public class V2rayConfig
{ {
public string? remarks { get; set; }
public Log4Ray log { get; set; } public Log4Ray log { get; set; }
public List<Inbounds4Ray> inbounds { get; set; }
public List<Outbounds4Ray> outbounds { get; set; }
public Stats4Ray? stats { get; set; }
public Metrics4Ray? metrics { get; set; }
public Policy4Ray? policy { get; set; }
public object dns { get; set; } public object dns { get; set; }
public List<Inbounds4Ray> inbounds { get; set; }
public List<Outbounds4Ray> outbounds { get; set; }
public Routing4Ray routing { get; set; } public Routing4Ray routing { get; set; }
public Metrics4Ray? metrics { get; set; }
public Policy4Ray? policy { get; set; }
public Stats4Ray? stats { get; set; }
public string? remarks { get; set; }
} }
public class Stats4Ray public class Stats4Ray

View File

@@ -61,7 +61,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Do you want to append rules? Choose yes to append, choose otherwise to replace 的本地化字符串。 /// 查找类似 Do you want to append rules? Choose yes to append, choose otherwise to replace. 的本地化字符串。
/// </summary> /// </summary>
public static string AddBatchRoutingRulesYesNo { public static string AddBatchRoutingRulesYesNo {
get { get {
@@ -196,7 +196,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Failed to run Core, please see the log 的本地化字符串。 /// 查找类似 Failed to run Core, please check the prompt information 的本地化字符串。
/// </summary> /// </summary>
public static string FailedToRunCore { public static string FailedToRunCore {
get { get {
@@ -403,7 +403,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Custom Icon 的本地化字符串。 /// 查找类似 Custom icon 的本地化字符串。
/// </summary> /// </summary>
public static string LvCustomIcon { public static string LvCustomIcon {
get { get {
@@ -610,7 +610,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 URL(Optional) 的本地化字符串。 /// 查找类似 URL (optional) 的本地化字符串。
/// </summary> /// </summary>
public static string LvUrl { public static string LvUrl {
get { get {
@@ -1006,7 +1006,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。 /// 查找类似 One-click multi-test latency and speed (Ctrl+E) 的本地化字符串。
/// </summary> /// </summary>
public static string menuMixedTestServer { public static string menuMixedTestServer {
get { get {
@@ -1311,6 +1311,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Remove invalid by test results 的本地化字符串。
/// </summary>
public static string menuRemoveInvalidServerResult {
get {
return ResourceManager.GetString("menuRemoveInvalidServerResult", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Remove selected servers (Delete) 的本地化字符串。 /// 查找类似 Remove selected servers (Delete) 的本地化字符串。
/// </summary> /// </summary>
@@ -1366,7 +1375,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Set as active rule(Enter) 的本地化字符串。 /// 查找类似 Set as active rule (Enter) 的本地化字符串。
/// </summary> /// </summary>
public static string menuRoutingAdvancedSetDefault { public static string menuRoutingAdvancedSetDefault {
get { get {
@@ -1680,6 +1689,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 By test result 的本地化字符串。
/// </summary>
public static string menuTestServerResult {
get {
return ResourceManager.GetString("menuTestServerResult", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 {0} Website 的本地化字符串。 /// 查找类似 {0} Website 的本地化字符串。
/// </summary> /// </summary>
@@ -1689,15 +1707,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Clear original subscription content 的本地化字符串。
/// </summary>
public static string MsgClearSubscription {
get {
return ResourceManager.GetString("MsgClearSubscription", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Download GeoFile: {0} successfully 的本地化字符串。 /// 查找类似 Download GeoFile: {0} successfully 的本地化字符串。
/// </summary> /// </summary>
@@ -2004,6 +2013,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Removed {0} invalid test results. 的本地化字符串。
/// </summary>
public static string RemoveInvalidServerResultTip {
get {
return ResourceManager.GetString("RemoveInvalidServerResultTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Are you sure to remove the rules? 的本地化字符串。 /// 查找类似 Are you sure to remove the rules? 的本地化字符串。
/// </summary> /// </summary>
@@ -2094,6 +2112,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Starting retesting failed parts, {0} remaining. Press ESC to terminate... 的本地化字符串。
/// </summary>
public static string SpeedtestingTestFailedPart {
get {
return ResourceManager.GetString("SpeedtestingTestFailedPart", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Waiting for testing (press ESC to terminate)... 的本地化字符串。 /// 查找类似 Waiting for testing (press ESC to terminate)... 的本地化字符串。
/// </summary> /// </summary>
@@ -2195,7 +2222,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 AutoRefresh 的本地化字符串。 /// 查找类似 Auto refresh 的本地化字符串。
/// </summary> /// </summary>
public static string TbAutoRefresh { public static string TbAutoRefresh {
get { get {
@@ -2204,7 +2231,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Auto ScrollToEnd 的本地化字符串。 /// 查找类似 Auto scroll to end 的本地化字符串。
/// </summary> /// </summary>
public static string TbAutoScrollToEnd { public static string TbAutoScrollToEnd {
get { get {
@@ -2294,7 +2321,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Support DnsObject, Click to view the document 的本地化字符串。 /// 查找类似 Supports DnsObject; Click to view documentation 的本地化字符串。
/// </summary> /// </summary>
public static string TbDnsObjectDoc { public static string TbDnsObjectDoc {
get { get {
@@ -2384,7 +2411,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Set directly by pressing the keyboard, take effect after restart 的本地化字符串。 /// 查找类似 Set directly by pressing the keyboard; Takes effect after restart 的本地化字符串。
/// </summary> /// </summary>
public static string TbGlobalHotkeySettingTip { public static string TbGlobalHotkeySettingTip {
get { get {
@@ -2663,7 +2690,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *Set the rules, separated by commas (,); The comma in the regular is replaced by &lt;COMMA&gt; 的本地化字符串。 /// 查找类似 *Separate rules by commas (,); For a literal comma use &lt;COMMA&gt;; Prefix # to ignore a rule 的本地化字符串。
/// </summary> /// </summary>
public static string TbRoutingTips { public static string TbRoutingTips {
get { get {
@@ -2771,7 +2798,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Automatic update interval of Geo (hours) 的本地化字符串。 /// 查找类似 Automatic update interval for Geo files (hours) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsAutoUpdateInterval { public static string TbSettingsAutoUpdateInterval {
get { get {
@@ -2843,7 +2870,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 FontFamily(Require restart) 的本地化字符串。 /// 查找类似 Font family (requires restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsCurrentFontFamily { public static string TbSettingsCurrentFontFamily {
get { get {
@@ -2852,7 +2879,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Install the font to the system and restart the settings 的本地化字符串。 /// 查找类似 Install the font to the system, select or fill in the font name, restart the settings 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsCurrentFontFamilyLinuxTip { public static string TbSettingsCurrentFontFamilyLinuxTip {
get { get {
@@ -2861,7 +2888,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Copy the font TTF/TTC file to the directory guiFonts, restart the settings 的本地化字符串。 /// 查找类似 Copy the font TTF/TTC file to the directory guiFonts; Reopen the settings window 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsCurrentFontFamilyTip { public static string TbSettingsCurrentFontFamilyTip {
get { get {
@@ -2915,7 +2942,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Display real-time speed 的本地化字符串。 /// 查找类似 Display real-time speed (requires restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsDisplayRealTimeSpeed { public static string TbSettingsDisplayRealTimeSpeed {
get { get {
@@ -2951,7 +2978,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Double-click server make active 的本地化字符串。 /// 查找类似 Double-clicking server makes it active 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsDoubleClick2Activate { public static string TbSettingsDoubleClick2Activate {
get { get {
@@ -2960,7 +2987,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Automatically adjust column width after updating subscription 的本地化字符串。 /// 查找类似 Automatically adjust column width after subscription update 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsEnableAutoAdjustMainLvColWidth { public static string TbSettingsEnableAutoAdjustMainLvColWidth {
get { get {
@@ -2987,7 +3014,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Enable Server Drag Drop Sort(Require restart) 的本地化字符串。 /// 查找类似 Enable sorting servers by drag-n-drop (requires restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsEnableDragDropSort { public static string TbSettingsEnableDragDropSort {
get { get {
@@ -3023,7 +3050,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Enable hardware acceleration(Require restart) 的本地化字符串。 /// 查找类似 Enable hardware acceleration (requires restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsEnableHWA { public static string TbSettingsEnableHWA {
get { get {
@@ -3059,7 +3086,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Exception. Do not use proxy server for addresses beginning with,Use semicolon (;) 的本地化字符串。 /// 查找类似 Exclusions: Do not use proxy server for addresses beginning with the following. Use semicolon (;) to separate entries. 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsExceptionTip { public static string TbSettingsExceptionTip {
get { get {
@@ -3068,7 +3095,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Exception. Do not use proxy server for addresses,with a comma (,) 的本地化字符串。 /// 查找类似 Exclusions: Do not use proxy server for the following addresses. Use comma (,) to separate entries. 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsExceptionTip2 { public static string TbSettingsExceptionTip2 {
get { get {
@@ -3103,15 +3130,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 HTTP Port 的本地化字符串。
/// </summary>
public static string TbSettingsHttpPort {
get {
return ResourceManager.GetString("TbSettingsHttpPort", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Hysteria Max bandwidth (Up/Dw) 的本地化字符串。 /// 查找类似 Hysteria Max bandwidth (Up/Dw) 的本地化字符串。
/// </summary> /// </summary>
@@ -3122,7 +3140,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Keep older when deduplication 的本地化字符串。 /// 查找类似 Keep the older when de-duplicating 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsKeepOlderDedupl { public static string TbSettingsKeepOlderDedupl {
get { get {
@@ -3167,7 +3185,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。 /// 查找类似 The password is encrypted and stored only in local files 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLinuxSudoPasswordTip { public static string TbSettingsLinuxSudoPasswordTip {
get { get {
@@ -3203,7 +3221,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Main layout orientation(Require restart) 的本地化字符串。 /// 查找类似 Main layout orientation (requires restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsMainGirdOrientation { public static string TbSettingsMainGirdOrientation {
get { get {
@@ -3211,6 +3229,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 The number of concurrent during multi-test 的本地化字符串。
/// </summary>
public static string TbSettingsMixedConcurrencyCount {
get {
return ResourceManager.GetString("TbSettingsMixedConcurrencyCount", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 sing-box Mux Protocol 的本地化字符串。 /// 查找类似 sing-box Mux Protocol 的本地化字符串。
/// </summary> /// </summary>
@@ -3346,15 +3373,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Number per time for auto batch during speedtest(max 1000) 的本地化字符串。
/// </summary>
public static string TbSettingsSpeedTestPageSize {
get {
return ResourceManager.GetString("TbSettingsSpeedTestPageSize", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。 /// 查找类似 SpeedTest Single Timeout Value 的本地化字符串。
/// </summary> /// </summary>
@@ -3401,7 +3419,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Enable traffic statistics (Require restart) 的本地化字符串。 /// 查找类似 Enable traffic statistics (requires restart) 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsStatistics { public static string TbSettingsStatistics {
get { get {
@@ -3868,15 +3886,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it! 的本地化字符串。
/// </summary>
public static string UpdateStandalonePackageTip {
get {
return ResourceManager.GetString("UpdateStandalonePackageTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 UpgradeApp does not exist 的本地化字符串。 /// 查找类似 UpgradeApp does not exist 的本地化字符串。
/// </summary> /// </summary>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@@ -210,9 +210,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>جابجایی</value> <value>جابجایی</value>
</data> </data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>محتوای اشتراک اصلی را پاک کنید</value>
</data>
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
<value>دانلود Core با موفقیت</value> <value>دانلود Core با موفقیت</value>
</data> </data>
@@ -344,10 +341,10 @@
<value>لطفاً DNS سفارشی صحیح را پر کنید</value> <value>لطفاً DNS سفارشی صحیح را پر کنید</value>
</data> </data>
<data name="TransportPathTip1" xml:space="preserve"> <data name="TransportPathTip1" xml:space="preserve">
<value>*ws path</value> <value>* مسیر ws</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>* مسیر h2</value>
</data> </data>
<data name="TransportPathTip3" xml:space="preserve"> <data name="TransportPathTip3" xml:space="preserve">
<value>*QUIC key/Kcp seed</value> <value>*QUIC key/Kcp seed</value>
@@ -356,13 +353,13 @@
<value>*grpc serviceName</value> <value>*grpc serviceName</value>
</data> </data>
<data name="TransportRequestHostTip1" xml:space="preserve"> <data name="TransportRequestHostTip1" xml:space="preserve">
<value>*http host Separated by commas (,)</value> <value>*هاست http جدا شده با کاما (،)</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws host</value> <value>*هاست ws</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host Separated by commas (,)</value> <value>*هاست h2 با کاما (،) جدا شده است</value>
</data> </data>
<data name="TransportRequestHostTip4" xml:space="preserve"> <data name="TransportRequestHostTip4" xml:space="preserve">
<value>*QUIC securty</value> <value>*QUIC securty</value>
@@ -377,7 +374,7 @@
<value>*QUIC camouflage type</value> <value>*QUIC camouflage type</value>
</data> </data>
<data name="TransportHeaderTypeTip4" xml:space="preserve"> <data name="TransportHeaderTypeTip4" xml:space="preserve">
<value>*grpc mode</value> <value>*حالت grpc</value>
</data> </data>
<data name="LvTLS" xml:space="preserve"> <data name="LvTLS" xml:space="preserve">
<value>TLS</value> <value>TLS</value>
@@ -404,7 +401,7 @@
<value>درحال تست کردن...</value> <value>درحال تست کردن...</value>
</data> </data>
<data name="LabLAN" xml:space="preserve"> <data name="LabLAN" xml:space="preserve">
<value>LAN</value> <value>شبکه محلی</value>
</data> </data>
<data name="LabLocal" xml:space="preserve"> <data name="LabLocal" xml:space="preserve">
<value>محلی</value> <value>محلی</value>
@@ -683,7 +680,7 @@
<value>راه اندازی مخفی کردن خودکار</value> <value>راه اندازی مخفی کردن خودکار</value>
</data> </data>
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve"> <data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>فاصله به روز رسانی خودکار و Geo (ساعت)</value> <value>فاصله به روز رسانی خودکار برای فایل های Geo (ساعت)</value>
</data> </data>
<data name="TbSettingsCore" xml:space="preserve"> <data name="TbSettingsCore" xml:space="preserve">
<value>هسته: تنظیمات اولیه</value> <value>هسته: تنظیمات اولیه</value>
@@ -704,7 +701,7 @@
<value>Outbound Freedom domainStrategy</value> <value>Outbound Freedom domainStrategy</value>
</data> </data>
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve"> <data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
<value>پس از به‌روزرسانی اشتراک، عرض ستون را به صورت خودکار تنظیم شود</value> <value>پس از به‌روزرسانی اشتراک، عرض ستون به صورت خودکار تنظیم شود</value>
</data> </data>
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve"> <data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
<value>به روز رسانی های پیش از انتشار را بررسی شود</value> <value>به روز رسانی های پیش از انتشار را بررسی شود</value>
@@ -713,16 +710,13 @@
<value>استثنا</value> <value>استثنا</value>
</data> </data>
<data name="TbSettingsExceptionTip" xml:space="preserve"> <data name="TbSettingsExceptionTip" xml:space="preserve">
<value>استثنا: از سرور پروکسی برای آدرس هایی که با شروع می شوند استفاده نکنید، از نقطه ویرگول (;) استفاده کنید.</value> <value>استثناها: از سرور پروکسی برای آدرس هایی که با موارد زیر شروع می شوند استفاده نکنید. برای جدا کردن ورودی ها از نقطه ویرگول (;) استفاده کنید.</value>
</data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>پورت Http</value>
</data> </data>
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve"> <data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
<value>Display real-time speed</value> <value>نمایش سرعت واقعی (نیاز به راه اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve"> <data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>هنگام کپی برداری، نگه داری قدیمی تر ها</value> <value>هنگام حذف کپی، قدیمی تر را نگه دارید</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>ثبت گزارش های محلی</value> <value>ثبت گزارش های محلی</value>
@@ -755,7 +749,7 @@
<value>درهنگام راه ائدازی شروع شود</value> <value>درهنگام راه ائدازی شروع شود</value>
</data> </data>
<data name="TbSettingsStatistics" xml:space="preserve"> <data name="TbSettingsStatistics" xml:space="preserve">
<value>فعال کردن آمار (نیاز به راه اندازی مجدد)</value> <value>فعال کردن آمار ترافیک (نیاز به راه اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsSubConvert" xml:space="preserve"> <data name="TbSettingsSubConvert" xml:space="preserve">
<value>آدرس اینترنتی تبدیل اشتراک</value> <value>آدرس اینترنتی تبدیل اشتراک</value>
@@ -863,7 +857,7 @@
<value>لیست مجموعه قوانین از پیش تعریف شده</value> <value>لیست مجموعه قوانین از پیش تعریف شده</value>
</data> </data>
<data name="TbRoutingTips" xml:space="preserve"> <data name="TbRoutingTips" xml:space="preserve">
<value>*قوانین را تنظیم کنید که با کاما از هم جدا شده اند (,); کاما در حالت عادی با &lt;COMMA&gt;</value> <value>*قوانین را با کاما (,) جدا کنید. برای کاما به معنای واقعی کلمه از &lt;COMMA&gt;; پیشوند # برای نادیده گرفتن یک قانون</value>
</data> </data>
<data name="menuImportRulesFromClipboard" xml:space="preserve"> <data name="menuImportRulesFromClipboard" xml:space="preserve">
<value>وارد کردن قوانین از کلیپ بورد</value> <value>وارد کردن قوانین از کلیپ بورد</value>
@@ -899,7 +893,7 @@
<value>مستندات شی قانون</value> <value>مستندات شی قانون</value>
</data> </data>
<data name="TbDnsObjectDoc" xml:space="preserve"> <data name="TbDnsObjectDoc" xml:space="preserve">
<value>پشتیبانی از DnsObject</value> <value>پشتیبانی از DnsObject. برای مشاهده مستندات کلیک کنید</value>
</data> </data>
<data name="SubUrlTips" xml:space="preserve"> <data name="SubUrlTips" xml:space="preserve">
<value>گروه لطفا اینجا را خالی بگذارید</value> <value>گروه لطفا اینجا را خالی بگذارید</value>
@@ -950,7 +944,7 @@
<value>این پارامتر فقط برای tcp/http و ws معتبر است</value> <value>این پارامتر فقط برای tcp/http و ws معتبر است</value>
</data> </data>
<data name="TbSettingsEnableHWA" xml:space="preserve"> <data name="TbSettingsEnableHWA" xml:space="preserve">
<value>فعال‌ سازی شتاب‌ دهنده سخت‌افزاری (نیاز به راه‌اندازی مجدد)</value> <value>فعال‌ سازی شتاب‌ دهنده سخت‌ افزاری (نیاز به راه‌اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve"> <data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value> <value>فعال کردن کش فایل مجموعه قوانین برای sing-box</value>
@@ -1051,9 +1045,6 @@
<data name="menuShowOrHideMainWindow" xml:space="preserve"> <data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>نمایش یا پنهان کردن پنجره اصلی</value> <value>نمایش یا پنهان کردن پنجره اصلی</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>شما در حال حاضر در حال اجرای یک بسته مستقل هستید، لطفاً فایل SelfContained.7z را به صورت دستی دانلود کنید تا آن را از حالت فشرده خارج کرده و بازنویسی کنید!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>پیکربندی سفارشی ساکس پورت</value> <value>پیکربندی سفارشی ساکس پورت</value>
</data> </data>
@@ -1208,7 +1199,7 @@
<value>انتقال به گروه</value> <value>انتقال به گروه</value>
</data> </data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve"> <data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>فعال کردن مرتب سازی با کشیدن سرور (نیاز به راه اندازی مجدد)</value> <value>فعال کردن مرتبسازی سرورها با کشیدن و رها کردن (نیاز به راهاندازی مجدد)</value>
</data> </data>
<data name="TbAutoRefresh" xml:space="preserve"> <data name="TbAutoRefresh" xml:space="preserve">
<value>بازخوانی خودکار</value> <value>بازخوانی خودکار</value>
@@ -1220,7 +1211,7 @@
<value>ویرایش سرور (Ctrl+D)</value> <value>ویرایش سرور (Ctrl+D)</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>روی server make active دوبار کلیک کنید</value> <value>دوبار کلیک کردن سرور باعث فعال شدن آن می شود</value>
</data> </data>
<data name="SpeedtestingCompleted" xml:space="preserve"> <data name="SpeedtestingCompleted" xml:space="preserve">
<value>تست تکمیل شد</value> <value>تست تکمیل شد</value>
@@ -1232,7 +1223,7 @@
<value>FontFamily (نیاز به راه اندازی مجدد)</value> <value>FontFamily (نیاز به راه اندازی مجدد)</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>فایل TTF/TTC فونت را در دایرکتوری guiFonts کپی کنید، تنظیمات را مجددا راه اندازی کنید</value> <value>فایل TTF/TTC فونت را در دایرکتوری guiFonts کپی کنید. پنجره تنظیمات را دوباره باز کنید</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve"> <data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>پورت Pac = +3; پورت Xray API = +4; پورت mihomo API = +5;</value> <value>پورت Pac = +3; پورت Xray API = +4; پورت mihomo API = +5;</value>
@@ -1372,11 +1363,11 @@
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>هنگام بستن پنجره در سینی پنهان شوید</value> <value>هنگام بستن پنجره در سینی پنهان شوید</value>
</data> </data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve"> <data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
<value>تعداد در هر زمان برای دسته خودکار در طول تست سرعت (حداکثر 1000)</value> <value>The number of concurrent during multi-test</value>
</data> </data>
<data name="TbSettingsExceptionTip2" xml:space="preserve"> <data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>استثنا:از سرور پروکسی برای آدرس ها، با کاما (،) استفاده نکنید</value> <value>موارد استثنا: از سرور پروکسی برای آدرس های زیر استفاده نکنید. برای جدا کردن ورودی ها از کاما (،) استفاده کنید.</value>
</data> </data>
<data name="TbSettingsDestOverride" xml:space="preserve"> <data name="TbSettingsDestOverride" xml:space="preserve">
<value>نوع Sniffing</value> <value>نوع Sniffing</value>
@@ -1393,4 +1384,16 @@
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve"> <data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
<value>کپی کردن دستور پروکسی در کلیپ بورد</value> <value>کپی کردن دستور پروکسی در کلیپ بورد</value>
</data> </data>
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
<value>شروع آزمایش مجدد قطعات ناموفق، {0} باقی مانده است. برای خاتمه ESC را فشار دهید...</value>
</data>
<data name="menuTestServerResult" xml:space="preserve">
<value>By test result</value>
</data>
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
<value>Remove invalid by test results</value>
</data>
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value>
</data>
</root> </root>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@@ -210,9 +210,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>Szállítás</value> <value>Szállítás</value>
</data> </data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>Eredeti előfizetési tartalom törlése</value>
</data>
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
<value>A Core letöltése sikerült</value> <value>A Core letöltése sikerült</value>
</data> </data>
@@ -715,9 +712,6 @@
<data name="TbSettingsExceptionTip" xml:space="preserve"> <data name="TbSettingsExceptionTip" xml:space="preserve">
<value>Kivétel. Ne használjon proxy szervert a címek esetében, amelyek pontosan itt kezdődnek, használjon pontosvesszőt (;)</value> <value>Kivétel. Ne használjon proxy szervert a címek esetében, amelyek pontosan itt kezdődnek, használjon pontosvesszőt (;)</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>HTTP Port</value>
</data>
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve"> <data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
<value>Display real-time speed</value> <value>Display real-time speed</value>
</data> </data>
@@ -1255,9 +1249,6 @@
<data name="menuShowOrHideMainWindow" xml:space="preserve"> <data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Fő ablak megjelenítése vagy elrejtése</value> <value>Fő ablak megjelenítése vagy elrejtése</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>Jelenleg egy önálló csomagot futtatsz, kérlek, töltsd le manuálisan a SelfContained.7z fájlt, bontsd ki és írd felül!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Testreszabott konfigurációs socks port</value> <value>Testreszabott konfigurációs socks port</value>
</data> </data>
@@ -1372,8 +1363,8 @@
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Minimálás tálcára ablak zárásakor</value> <value>Minimálás tálcára ablak zárásakor</value>
</data> </data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve"> <data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
<value>Szám / időszak az automatikus batch során a sebességvizsgálat során (maximum 1000)</value> <value>The number of concurrent during multi-test</value>
</data> </data>
<data name="TbSettingsExceptionTip2" xml:space="preserve"> <data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>Kivétel. Ne használj proxy szervert a címeknél, évezz pontosvesszőt (,)</value> <value>Kivétel. Ne használj proxy szervert a címeknél, évezz pontosvesszőt (,)</value>
@@ -1393,4 +1384,16 @@
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve"> <data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
<value>Copy proxy command to clipboard</value> <value>Copy proxy command to clipboard</value>
</data> </data>
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
</data>
<data name="menuTestServerResult" xml:space="preserve">
<value>By test result</value>
</data>
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
<value>Remove invalid by test results</value>
</data>
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value>
</data>
</root> </root>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@@ -210,9 +210,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>Transport</value> <value>Transport</value>
</data> </data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>Clear original subscription content</value>
</data>
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
<value>Download Core successfully</value> <value>Download Core successfully</value>
</data> </data>
@@ -320,7 +317,7 @@
<value>Remarks</value> <value>Remarks</value>
</data> </data>
<data name="LvUrl" xml:space="preserve"> <data name="LvUrl" xml:space="preserve">
<value>URL(Optional)</value> <value>URL (optional)</value>
</data> </data>
<data name="LvCount" xml:space="preserve"> <data name="LvCount" xml:space="preserve">
<value>Count</value> <value>Count</value>
@@ -329,7 +326,7 @@
<value>Please fill in the URL</value> <value>Please fill in the URL</value>
</data> </data>
<data name="AddBatchRoutingRulesYesNo" xml:space="preserve"> <data name="AddBatchRoutingRulesYesNo" xml:space="preserve">
<value>Do you want to append rules? Choose yes to append, choose otherwise to replace</value> <value>Do you want to append rules? Choose yes to append, choose otherwise to replace.</value>
</data> </data>
<data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve"> <data name="MsgDownloadGeoFileSuccessfully" xml:space="preserve">
<value>Download GeoFile: {0} successfully</value> <value>Download GeoFile: {0} successfully</value>
@@ -338,7 +335,7 @@
<value>Information</value> <value>Information</value>
</data> </data>
<data name="LvCustomIcon" xml:space="preserve"> <data name="LvCustomIcon" xml:space="preserve">
<value>Custom Icon</value> <value>Custom icon</value>
</data> </data>
<data name="FillCorrectDNSText" xml:space="preserve"> <data name="FillCorrectDNSText" xml:space="preserve">
<value>Please fill in the correct custom DNS</value> <value>Please fill in the correct custom DNS</value>
@@ -683,7 +680,7 @@
<value>Auto hide startup</value> <value>Auto hide startup</value>
</data> </data>
<data name="TbSettingsAutoUpdateInterval" xml:space="preserve"> <data name="TbSettingsAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval of Geo (hours)</value> <value>Automatic update interval for Geo files (hours)</value>
</data> </data>
<data name="TbSettingsCore" xml:space="preserve"> <data name="TbSettingsCore" xml:space="preserve">
<value>Core: basic settings</value> <value>Core: basic settings</value>
@@ -704,7 +701,7 @@
<value>Outbound Freedom domainStrategy</value> <value>Outbound Freedom domainStrategy</value>
</data> </data>
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve"> <data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
<value>Automatically adjust column width after updating subscription</value> <value>Automatically adjust column width after subscription update</value>
</data> </data>
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve"> <data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
<value>Check for pre-release updates</value> <value>Check for pre-release updates</value>
@@ -713,16 +710,13 @@
<value>Exception</value> <value>Exception</value>
</data> </data>
<data name="TbSettingsExceptionTip" xml:space="preserve"> <data name="TbSettingsExceptionTip" xml:space="preserve">
<value>Exception. Do not use proxy server for addresses beginning with,Use semicolon (;)</value> <value>Exclusions: Do not use proxy server for addresses beginning with the following. Use semicolon (;) to separate entries.</value>
</data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>HTTP Port</value>
</data> </data>
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve"> <data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
<value>Display real-time speed (Require restart)</value> <value>Display real-time speed (requires restart)</value>
</data> </data>
<data name="TbSettingsKeepOlderDedupl" xml:space="preserve"> <data name="TbSettingsKeepOlderDedupl" xml:space="preserve">
<value>Keep older when deduplication</value> <value>Keep the older when de-duplicating</value>
</data> </data>
<data name="TbSettingsLogEnabled" xml:space="preserve"> <data name="TbSettingsLogEnabled" xml:space="preserve">
<value>Enable Log</value> <value>Enable Log</value>
@@ -755,7 +749,7 @@
<value>Start on boot</value> <value>Start on boot</value>
</data> </data>
<data name="TbSettingsStatistics" xml:space="preserve"> <data name="TbSettingsStatistics" xml:space="preserve">
<value>Enable traffic statistics (Require restart)</value> <value>Enable traffic statistics (requires restart)</value>
</data> </data>
<data name="TbSettingsSubConvert" xml:space="preserve"> <data name="TbSettingsSubConvert" xml:space="preserve">
<value>Subscription conversion URL</value> <value>Subscription conversion URL</value>
@@ -785,7 +779,7 @@
<value>Global Hotkey Settings</value> <value>Global Hotkey Settings</value>
</data> </data>
<data name="TbGlobalHotkeySettingTip" xml:space="preserve"> <data name="TbGlobalHotkeySettingTip" xml:space="preserve">
<value>Set directly by pressing the keyboard, take effect after restart</value> <value>Set directly by pressing the keyboard; Takes effect after restart</value>
</data> </data>
<data name="TbNotChangeSystemProxy" xml:space="preserve"> <data name="TbNotChangeSystemProxy" xml:space="preserve">
<value>Do not change system proxy</value> <value>Do not change system proxy</value>
@@ -842,7 +836,7 @@
<value>Remove selected (Delete)</value> <value>Remove selected (Delete)</value>
</data> </data>
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule(Enter)</value> <value>Set as active rule (Enter)</value>
</data> </data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>Domain Matcher</value> <value>Domain Matcher</value>
@@ -863,7 +857,7 @@
<value>Pre-defined Rule Set List</value> <value>Pre-defined Rule Set List</value>
</data> </data>
<data name="TbRoutingTips" xml:space="preserve"> <data name="TbRoutingTips" xml:space="preserve">
<value>*Set the rules, separated by commas (,); The comma in the regular is replaced by &lt;COMMA&gt;</value> <value>*Separate rules by commas (,); For a literal comma use &lt;COMMA&gt;; Prefix # to ignore a rule</value>
</data> </data>
<data name="menuImportRulesFromClipboard" xml:space="preserve"> <data name="menuImportRulesFromClipboard" xml:space="preserve">
<value>Import Rules From Clipboard</value> <value>Import Rules From Clipboard</value>
@@ -899,7 +893,7 @@
<value>Ruleobject Doc</value> <value>Ruleobject Doc</value>
</data> </data>
<data name="TbDnsObjectDoc" xml:space="preserve"> <data name="TbDnsObjectDoc" xml:space="preserve">
<value>Support DnsObject, Click to view the document</value> <value>Supports DnsObject; Click to view documentation</value>
</data> </data>
<data name="SubUrlTips" xml:space="preserve"> <data name="SubUrlTips" xml:space="preserve">
<value>For group please leave blank here</value> <value>For group please leave blank here</value>
@@ -917,7 +911,7 @@
<value>Do not use proxy servers for local (intranet) addresses</value> <value>Do not use proxy servers for local (intranet) addresses</value>
</data> </data>
<data name="menuMixedTestServer" xml:space="preserve"> <data name="menuMixedTestServer" xml:space="preserve">
<value>One-click multi test Latency and speed (Ctrl+E)</value> <value>One-click multi-test latency and speed (Ctrl+E)</value>
</data> </data>
<data name="LvTestDelay" xml:space="preserve"> <data name="LvTestDelay" xml:space="preserve">
<value>Delay(ms)</value> <value>Delay(ms)</value>
@@ -926,7 +920,7 @@
<value>Speed(M/s)</value> <value>Speed(M/s)</value>
</data> </data>
<data name="FailedToRunCore" xml:space="preserve"> <data name="FailedToRunCore" xml:space="preserve">
<value>Failed to run Core, please see the log</value> <value>Failed to run Core, please check the prompt information</value>
</data> </data>
<data name="LvFilter" xml:space="preserve"> <data name="LvFilter" xml:space="preserve">
<value>Remarks regular filter</value> <value>Remarks regular filter</value>
@@ -947,10 +941,10 @@
<value>Move to group</value> <value>Move to group</value>
</data> </data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve"> <data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Enable Server Drag Drop Sort(Require restart)</value> <value>Enable sorting servers by drag-n-drop (requires restart)</value>
</data> </data>
<data name="TbAutoRefresh" xml:space="preserve"> <data name="TbAutoRefresh" xml:space="preserve">
<value>AutoRefresh</value> <value>Auto refresh</value>
</data> </data>
<data name="SpeedtestingSkip" xml:space="preserve"> <data name="SpeedtestingSkip" xml:space="preserve">
<value>Skip test</value> <value>Skip test</value>
@@ -959,7 +953,7 @@
<value>Edit Server (Ctrl+D)</value> <value>Edit Server (Ctrl+D)</value>
</data> </data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve"> <data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Double-click server make active</value> <value>Double-clicking server makes it active</value>
</data> </data>
<data name="SpeedtestingCompleted" xml:space="preserve"> <data name="SpeedtestingCompleted" xml:space="preserve">
<value>Test completed</value> <value>Test completed</value>
@@ -974,10 +968,10 @@
<value>This parameter is valid only for tcp/http and ws</value> <value>This parameter is valid only for tcp/http and ws</value>
</data> </data>
<data name="TbSettingsCurrentFontFamily" xml:space="preserve"> <data name="TbSettingsCurrentFontFamily" xml:space="preserve">
<value>FontFamily(Require restart)</value> <value>Font family (requires restart)</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value> <value>Copy the font TTF/TTC file to the directory guiFonts; Reopen the settings window</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve"> <data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>Pac port = +3; Xray API port = +4; mihomo API port = +5;</value> <value>Pac port = +3; Xray API port = +4; mihomo API port = +5;</value>
@@ -1007,7 +1001,7 @@
<value>SpiderX</value> <value>SpiderX</value>
</data> </data>
<data name="TbSettingsEnableHWA" xml:space="preserve"> <data name="TbSettingsEnableHWA" xml:space="preserve">
<value>Enable hardware acceleration(Require restart)</value> <value>Enable hardware acceleration (requires restart)</value>
</data> </data>
<data name="SpeedtestingWait" xml:space="preserve"> <data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing (press ESC to terminate)...</value> <value>Waiting for testing (press ESC to terminate)...</value>
@@ -1115,7 +1109,7 @@
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value> <value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value>
</data> </data>
<data name="TbAutoScrollToEnd" xml:space="preserve"> <data name="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value> <value>Auto scroll to end</value>
</data> </data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</value> <value>Speed Ping Test URL</value>
@@ -1235,7 +1229,7 @@
<value>Multi-Server lowest latency</value> <value>Multi-Server lowest latency</value>
</data> </data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve"> <data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>Main layout orientation(Require restart)</value> <value>Main layout orientation (requires restart)</value>
</data> </data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve"> <data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>Multi-server load balancing</value> <value>Multi-server load balancing</value>
@@ -1255,9 +1249,6 @@
<data name="menuShowOrHideMainWindow" xml:space="preserve"> <data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value> <value>Show or hide the main window</value>
</data> </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"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</value> <value>Custom config socks port</value>
</data> </data>
@@ -1343,7 +1334,7 @@
<value>Please do not use the insecure HTTP protocol subscription address</value> <value>Please do not use the insecure HTTP protocol subscription address</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value> <value>Install the font to the system, select or fill in the font name, restart the settings</value>
</data> </data>
<data name="menuExitTips" xml:space="preserve"> <data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value> <value>Are you sure to exit?</value>
@@ -1355,7 +1346,7 @@
<value>System sudo password</value> <value>System sudo password</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value> <value>The password is encrypted and stored only in local files</value>
</data> </data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve"> <data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value> <value>Please set the sudo password in Tun mode settings first</value>
@@ -1372,11 +1363,11 @@
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value> <value>Hide to tray when closing the window</value>
</data> </data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve"> <data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
<value>Number per time for auto batch during speedtest(max 1000)</value> <value>The number of concurrent during multi-test</value>
</data> </data>
<data name="TbSettingsExceptionTip2" xml:space="preserve"> <data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value> <value>Exclusions: Do not use proxy server for the following addresses. Use comma (,) to separate entries.</value>
</data> </data>
<data name="TbSettingsDestOverride" xml:space="preserve"> <data name="TbSettingsDestOverride" xml:space="preserve">
<value>Sniffing type</value> <value>Sniffing type</value>
@@ -1393,4 +1384,16 @@
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve"> <data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
<value>Copy proxy command to clipboard</value> <value>Copy proxy command to clipboard</value>
</data> </data>
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
</data>
<data name="menuTestServerResult" xml:space="preserve">
<value>By test result</value>
</data>
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
<value>Remove invalid by test results</value>
</data>
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value>
</data>
</root> </root>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@@ -210,9 +210,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>Протокол</value> <value>Протокол</value>
</data> </data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>Очистить контент оригинальной подписки</value>
</data>
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
<value>Ядро успешно загружено</value> <value>Ядро успешно загружено</value>
</data> </data>
@@ -721,9 +718,6 @@
<data name="TbSettingsExceptionTip" xml:space="preserve"> <data name="TbSettingsExceptionTip" xml:space="preserve">
<value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value> <value>Исключение. Не используйте прокси-сервер для адресов, начинающихся с (,), используйте точку с запятой (;)</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>HTTP порт</value>
</data>
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve"> <data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
<value>Display real-time speed</value> <value>Display real-time speed</value>
</data> </data>
@@ -1210,9 +1204,6 @@
<data name="menuAddTuicServer" xml:space="preserve"> <data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] server</value> <value>Add [TUIC] server</value>
</data> </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"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value> <value>Enable IPv6 Address</value>
</data> </data>
@@ -1372,8 +1363,8 @@
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value> <value>Hide to tray when closing the window</value>
</data> </data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve"> <data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
<value>Number per time for auto batch during speedtest(max 1000)</value> <value>The number of concurrent during multi-test</value>
</data> </data>
<data name="TbSettingsExceptionTip2" xml:space="preserve"> <data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>Exception. Do not use proxy server for addresses,with a comma (,)</value> <value>Exception. Do not use proxy server for addresses,with a comma (,)</value>
@@ -1393,4 +1384,16 @@
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve"> <data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
<value>Copy proxy command to clipboard</value> <value>Copy proxy command to clipboard</value>
</data> </data>
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
<value>Starting retesting failed parts, {0} remaining. Press ESC to terminate...</value>
</data>
<data name="menuTestServerResult" xml:space="preserve">
<value>By test result</value>
</data>
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
<value>Remove invalid by test results</value>
</data>
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value>
</data>
</root> </root>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@@ -175,10 +175,10 @@
<value>初始化配置</value> <value>初始化配置</value>
</data> </data>
<data name="IsLatestCore" xml:space="preserve"> <data name="IsLatestCore" xml:space="preserve">
<value>{0} {1} 已是最新版本</value> <value>{0} {1} 已是最新版本</value>
</data> </data>
<data name="IsLatestN" xml:space="preserve"> <data name="IsLatestN" xml:space="preserve">
<value>{0} {1} 已是最新版本</value> <value>{0} {1} 已是最新版本</value>
</data> </data>
<data name="LvAddress" xml:space="preserve"> <data name="LvAddress" xml:space="preserve">
<value>地址</value> <value>地址</value>
@@ -210,9 +210,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>传输协议</value> <value>传输协议</value>
</data> </data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>清除原订阅内容</value>
</data>
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
<value>下载Core成功</value> <value>下载Core成功</value>
</data> </data>
@@ -277,7 +274,7 @@
<value>请先选择服务器</value> <value>请先选择服务器</value>
</data> </data>
<data name="RemoveDuplicateServerResult" xml:space="preserve"> <data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>服务器去重完成。原数量: {0},现数量: {1}</value> <value>服务器去重完成。原数量: {0},现数量: {1}</value>
</data> </data>
<data name="RemoveServer" xml:space="preserve"> <data name="RemoveServer" xml:space="preserve">
<value>是否确定移除服务器?</value> <value>是否确定移除服务器?</value>
@@ -715,9 +712,6 @@
<data name="TbSettingsExceptionTip" xml:space="preserve"> <data name="TbSettingsExceptionTip" xml:space="preserve">
<value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号(;)分隔。</value> <value>例外:对于下列字符开头的地址,不使用代理配置文件。使用分号(;)分隔。</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>本地http监听端口</value>
</data>
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve"> <data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
<value>显示实时速度(需重启)</value> <value>显示实时速度(需重启)</value>
</data> </data>
@@ -926,7 +920,7 @@
<value>速度(M/s)</value> <value>速度(M/s)</value>
</data> </data>
<data name="FailedToRunCore" xml:space="preserve"> <data name="FailedToRunCore" xml:space="preserve">
<value>运行Core失败请查看日志</value> <value>运行 Core 失败,请查看提示信息</value>
</data> </data>
<data name="LvFilter" xml:space="preserve"> <data name="LvFilter" xml:space="preserve">
<value>别名正则过滤</value> <value>别名正则过滤</value>
@@ -1252,9 +1246,6 @@
<data name="menuShowOrHideMainWindow" xml:space="preserve"> <data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>显示或隐藏主界面</value> <value>显示或隐藏主界面</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自定义配置的Socks端口</value> <value>自定义配置的Socks端口</value>
</data> </data>
@@ -1340,7 +1331,7 @@
<value>请不要使用不安全的HTTP协议订阅地址</value> <value>请不要使用不安全的HTTP协议订阅地址</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安装字体到系统中,重启设置</value> <value>安装字体到系统中,选择或填入字体名称,重启设置</value>
</data> </data>
<data name="menuExitTips" xml:space="preserve"> <data name="menuExitTips" xml:space="preserve">
<value>是否确定退出?</value> <value>是否确定退出?</value>
@@ -1369,8 +1360,8 @@
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>关闭窗口时隐藏至托盘</value> <value>关闭窗口时隐藏至托盘</value>
</data> </data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve"> <data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
<value>测试时自动分批的每批数量最大1000</value> <value>多线程测试时的并发数量</value>
</data> </data>
<data name="TbSettingsExceptionTip2" xml:space="preserve"> <data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>例外:对于下列地址不使用代理配置文件。使用逗号(,)分隔。</value> <value>例外:对于下列地址不使用代理配置文件。使用逗号(,)分隔。</value>
@@ -1390,4 +1381,16 @@
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve"> <data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
<value>复制终端代理命令至剪贴板</value> <value>复制终端代理命令至剪贴板</value>
</data> </data>
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
<value>开始对失败部分进行重新测试,剩余 {0} 个。可按 ESC 终止...</value>
</data>
<data name="menuTestServerResult" xml:space="preserve">
<value>按测试结果</value>
</data>
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
<value>按测试结果移除无效</value>
</data>
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>移除无效测试结果 {0} 个。</value>
</data>
</root> </root>

View File

@@ -175,10 +175,10 @@
<value>初始化設定</value> <value>初始化設定</value>
</data> </data>
<data name="IsLatestCore" xml:space="preserve"> <data name="IsLatestCore" xml:space="preserve">
<value>{0} {1} 已是最新版本</value> <value>{0} {1} 已是最新版本</value>
</data> </data>
<data name="IsLatestN" xml:space="preserve"> <data name="IsLatestN" xml:space="preserve">
<value>{0} {1} 已是最新版本</value> <value>{0} {1} 已是最新版本</value>
</data> </data>
<data name="LvAddress" xml:space="preserve"> <data name="LvAddress" xml:space="preserve">
<value>位址</value> <value>位址</value>
@@ -210,9 +210,6 @@
<data name="LvTransportProtocol" xml:space="preserve"> <data name="LvTransportProtocol" xml:space="preserve">
<value>傳輸協定</value> <value>傳輸協定</value>
</data> </data>
<data name="MsgClearSubscription" xml:space="preserve">
<value>清除原訂閱內容</value>
</data>
<data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve"> <data name="MsgDownloadV2rayCoreSuccessfully" xml:space="preserve">
<value>下載Core成功</value> <value>下載Core成功</value>
</data> </data>
@@ -277,7 +274,7 @@
<value>請先選擇伺服器</value> <value>請先選擇伺服器</value>
</data> </data>
<data name="RemoveDuplicateServerResult" xml:space="preserve"> <data name="RemoveDuplicateServerResult" xml:space="preserve">
<value>伺服器去重完成。原數量: {0},現數量: {1}</value> <value>伺服器去重完成。原數量: {0},現數量: {1}</value>
</data> </data>
<data name="RemoveServer" xml:space="preserve"> <data name="RemoveServer" xml:space="preserve">
<value>是否確定移除伺服器?</value> <value>是否確定移除伺服器?</value>
@@ -716,9 +713,6 @@
<data name="TbSettingsExceptionTip" xml:space="preserve"> <data name="TbSettingsExceptionTip" xml:space="preserve">
<value>例外:對於下列字元開頭的位址,不使用代理設定檔。使用分號(;)分隔。</value> <value>例外:對於下列字元開頭的位址,不使用代理設定檔。使用分號(;)分隔。</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>本機HTTP偵聽埠</value>
</data>
<data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve"> <data name="TbSettingsDisplayRealTimeSpeed" xml:space="preserve">
<value>顯示即時速度(需重啟)</value> <value>顯示即時速度(需重啟)</value>
</data> </data>
@@ -927,7 +921,7 @@
<value>速度(M/s)</value> <value>速度(M/s)</value>
</data> </data>
<data name="FailedToRunCore" xml:space="preserve"> <data name="FailedToRunCore" xml:space="preserve">
<value>執行Core失敗請查閲日誌</value> <value>執行Core失敗請查看提示訊息</value>
</data> </data>
<data name="LvFilter" xml:space="preserve"> <data name="LvFilter" xml:space="preserve">
<value>別名正則過濾</value> <value>別名正則過濾</value>
@@ -1133,9 +1127,6 @@
<data name="menuShowOrHideMainWindow" xml:space="preserve"> <data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>顯示或隱藏主介面</value> <value>顯示或隱藏主介面</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂設定的Socks連接埠</value> <value>自訂設定的Socks連接埠</value>
</data> </data>
@@ -1221,7 +1212,7 @@
<value>請不要使用不安全的HTTP協定訂閱位址</value> <value>請不要使用不安全的HTTP協定訂閱位址</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安裝字到系統中,重新啟動設定</value> <value>安裝字到系統中,選擇或填入字體名稱,重新啟動設定</value>
</data> </data>
<data name="menuExitTips" xml:space="preserve"> <data name="menuExitTips" xml:space="preserve">
<value>是否確定退出?</value> <value>是否確定退出?</value>
@@ -1370,8 +1361,8 @@
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve"> <data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>關閉視窗時隱藏至托盤</value> <value>關閉視窗時隱藏至托盤</value>
</data> </data>
<data name="TbSettingsSpeedTestPageSize" xml:space="preserve"> <data name="TbSettingsMixedConcurrencyCount" xml:space="preserve">
<value>測試時自動分批的每批數量最大1000</value> <value>多執行緒測試時的並發數量</value>
</data> </data>
<data name="TbSettingsExceptionTip2" xml:space="preserve"> <data name="TbSettingsExceptionTip2" xml:space="preserve">
<value>例外:對於下列位址不使用代理設定檔,使用逗號(,)分隔。</value> <value>例外:對於下列位址不使用代理設定檔,使用逗號(,)分隔。</value>
@@ -1391,4 +1382,16 @@
<data name="menuCopyProxyCmdToClipboard" xml:space="preserve"> <data name="menuCopyProxyCmdToClipboard" xml:space="preserve">
<value>複製終端代理指令至剪貼簿</value> <value>複製終端代理指令至剪貼簿</value>
</data> </data>
<data name="SpeedtestingTestFailedPart" xml:space="preserve">
<value>開始對失敗部分進行重新測試,剩餘 {0} 個。可按 ESC 終止...</value>
</data>
<data name="menuTestServerResult" xml:space="preserve">
<value>按測試結果</value>
</data>
<data name="menuRemoveInvalidServerResult" xml:space="preserve">
<value>按測試結果移除無效</value>
</data>
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>移除無效測試結果 {0} 個。</value>
</data>
</root> </root>

View File

@@ -0,0 +1,118 @@
#!/bin/bash
# Function to set proxy for GNOME
set_gnome_proxy() {
local MODE=$1
local PROXY_IP=$2
local PROXY_PORT=$3
local IGNORE_HOSTS=$4
# Set the proxy mode
gsettings set org.gnome.system.proxy mode "$MODE"
if [ "$MODE" == "manual" ]; then
# List of protocols
local PROTOCOLS=("http" "https" "ftp" "socks")
# Loop through protocols to set the proxy
for PROTOCOL in "${PROTOCOLS[@]}"; do
gsettings set org.gnome.system.proxy.$PROTOCOL host "$PROXY_IP"
gsettings set org.gnome.system.proxy.$PROTOCOL port "$PROXY_PORT"
done
# Set ignored hosts
gsettings set org.gnome.system.proxy ignore-hosts "['$IGNORE_HOSTS']"
echo "GNOME: Manual proxy settings applied."
echo "Proxy IP: $PROXY_IP"
echo "Proxy Port: $PROXY_PORT"
echo "Ignored Hosts: $IGNORE_HOSTS"
elif [ "$MODE" == "none" ]; then
echo "GNOME: Proxy disabled."
else
echo "GNOME: Invalid mode. Use 'none' or 'manual'."
exit 1
fi
}
# Function to set proxy for KDE
set_kde_proxy() {
local MODE=$1
local PROXY_IP=$2
local PROXY_PORT=$3
local IGNORE_HOSTS=$4
# Determine the correct kwriteconfig command based on KDE_SESSION_VERSION
if [ "$KDE_SESSION_VERSION" == "6" ]; then
KWRITECONFIG="kwriteconfig6"
else
KWRITECONFIG="kwriteconfig5"
fi
# KDE uses kwriteconfig to modify proxy settings
if [ "$MODE" == "manual" ]; then
# Set proxy for all protocols
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 1
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key httpProxy "http://$PROXY_IP:$PROXY_PORT"
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key httpsProxy "http://$PROXY_IP:$PROXY_PORT"
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ftpProxy "http://$PROXY_IP:$PROXY_PORT"
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key socksProxy "http://$PROXY_IP:$PROXY_PORT"
# Set ignored hosts
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key NoProxyFor "$IGNORE_HOSTS"
echo "KDE: Manual proxy settings applied."
echo "Proxy IP: $PROXY_IP"
echo "Proxy Port: $PROXY_PORT"
echo "Ignored Hosts: $IGNORE_HOSTS"
elif [ "$MODE" == "none" ]; then
# Disable proxy
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 0
echo "KDE: Proxy disabled."
else
echo "KDE: Invalid mode. Use 'none' or 'manual'."
exit 1
fi
# Apply changes by restarting KDE's network settings
dbus-send --type=signal /KIO/Scheduler org.kde.KIO.Scheduler.reparseSlaveConfiguration string:""
}
# Detect the current desktop environment
detect_desktop_environment() {
if [ "$XDG_CURRENT_DESKTOP" == "GNOME" ] || [ "$XDG_CURRENT_DESKTOP" == "ubuntu:GNOME" ] || [ "$XDG_SESSION_DESKTOP" == "GNOME" ] || [ "$XDG_SESSION_DESKTOP" == "ubuntu:GNOME" ]; then
echo "gnome"
elif [ "$XDG_CURRENT_DESKTOP" == "KDE" ] || [ "$XDG_CURRENT_DESKTOP" == "plasma" ] || [ "$XDG_SESSION_DESKTOP" == "KDE" ] || [ "$XDG_SESSION_DESKTOP" == "plasma" ]; then
echo "kde"
else
echo "unsupported"
fi
}
# Main script logic
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <mode> [proxy_ip proxy_port ignore_hosts]"
echo " mode: 'none' or 'manual'"
echo " If mode is 'manual', provide proxy IP, port, and ignore hosts."
exit 1
fi
# Get the mode
MODE=$1
PROXY_IP=$2
PROXY_PORT=$3
IGNORE_HOSTS=$4
# Detect desktop environment
DE=$(detect_desktop_environment)
# Apply settings based on the desktop environment
if [ "$DE" == "gnome" ]; then
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
elif [ "$DE" == "kde" ]; then
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
set_kde_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
else
echo "Unsupported desktop environment: $DE"
exit 1
fi

View File

@@ -0,0 +1,74 @@
#!/bin/bash
# Function to set proxy
set_proxy() {
PROXY_IP=$1
PROXY_PORT=$2
shift 2
BYPASS_DOMAINS=("$@")
# If no bypass domains are provided, set it to empty by default
if [ ${#BYPASS_DOMAINS[@]} -eq 0 ]; then
BYPASS_DOMAINS=("")
fi
# Get all network service names
SERVICES=$(networksetup -listallnetworkservices | grep -v '*')
# Loop through each network service
echo "$SERVICES" | while read -r SERVICE; do
echo "Setting proxy for network service '$SERVICE'..."
# Set HTTP proxy
networksetup -setwebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
# Set HTTPS proxy
networksetup -setsecurewebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
# Set SOCKS proxy
networksetup -setsocksfirewallproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
# Set bypass domains
networksetup -setproxybypassdomains "$SERVICE" "${BYPASS_DOMAINS[@]}"
echo "Proxy for network service '$SERVICE' has been set to $PROXY_IP:$PROXY_PORT"
done
echo "Proxy settings for all network services are complete!"
}
# Function to disable proxy
clear_proxy() {
# Get all network service names
SERVICES=$(networksetup -listallnetworkservices | grep -v '*')
# Loop through each network service
echo "$SERVICES" | while read -r SERVICE; do
echo "Disabling proxy and clearing bypass domains for network service '$SERVICE'..."
# Disable HTTP proxy
networksetup -setwebproxystate "$SERVICE" off
# Disable HTTPS proxy
networksetup -setsecurewebproxystate "$SERVICE" off
# Disable SOCKS proxy
networksetup -setsocksfirewallproxystate "$SERVICE" off
echo "Proxy for network service '$SERVICE' has been disabled"
done
echo "Proxy for all network services has been disabled!"
}
# Main script logic
if [ "$1" == "set" ]; then
# Check if enough parameters are passed for setting proxy
if [ "$#" -lt 3 ]; then
echo "Usage: $0 set <IP Address> <Port> [Bypass Domain 1 Bypass Domain 2 ...]"
exit 1
fi
set_proxy "$2" "$3" "${@:4}"
elif [ "$1" == "clear" ]; then
clear_proxy
else
echo "Usage:"
echo " To set proxy: $0 set <IP Address> <Port> [Bypass Domain 1 Bypass Domain 2 ...]"
echo " To clear proxy: $0 clear"
exit 1
fi

View File

@@ -1,26 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <OutputType>Library</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>7.6.2</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Downloader" Version="3.3.1" /> <PackageReference Include="Downloader" />
<PackageReference Include="ReactiveUI" Version="20.1.63" /> <PackageReference Include="ReactiveUI">
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" /> <TreatAsUsed>true</TreatAsUsed>
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" /> </PackageReference>
<PackageReference Include="Splat.NLog" Version="15.2.22" /> <PackageReference Include="ReactiveUI.Fody" />
<PackageReference Include="WebDav.Client" Version="2.8.0" /> <PackageReference Include="sqlite-net-pcl" />
<PackageReference Include="YamlDotNet" Version="16.3.0" /> <PackageReference Include="Splat.NLog" />
<PackageReference Include="QRCoder" Version="1.6.0" /> <PackageReference Include="WebDav.Client" />
<PackageReference Include="CliWrap" Version="3.7.0" /> <PackageReference Include="YamlDotNet" />
<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" /> <PackageReference Include="QRCoder" />
<PackageReference Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" /> <PackageReference Include="CliWrap" />
<PackageReference Include="TaskScheduler" Version="2.11.0" /> <PackageReference Include="ZXing.Net.Bindings.SkiaSharp" />
<PackageReference Include="TaskScheduler" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -32,6 +29,8 @@
<EmbeddedResource Include="Sample\dns_singbox_normal" /> <EmbeddedResource Include="Sample\dns_singbox_normal" />
<EmbeddedResource Include="Sample\dns_v2ray_normal" /> <EmbeddedResource Include="Sample\dns_v2ray_normal" />
<EmbeddedResource Include="Sample\pac" /> <EmbeddedResource Include="Sample\pac" />
<EmbeddedResource Include="Sample\proxy_set_linux_sh" />
<EmbeddedResource Include="Sample\proxy_set_osx_sh" />
<EmbeddedResource Include="Sample\SampleClientConfig" /> <EmbeddedResource Include="Sample\SampleClientConfig" />
<EmbeddedResource Include="Sample\SampleHttpRequest" /> <EmbeddedResource Include="Sample\SampleHttpRequest" />
<EmbeddedResource Include="Sample\SampleHttpResponse" /> <EmbeddedResource Include="Sample\SampleHttpResponse" />
@@ -51,9 +50,6 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
</Compile> </Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resx\ResUI.fa-Ir.resx"> <EmbeddedResource Update="Resx\ResUI.fa-Ir.resx">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>PublicResXFileCodeGenerator</Generator> <Generator>PublicResXFileCodeGenerator</Generator>

View File

@@ -116,7 +116,7 @@ namespace ServiceLib.Services.CoreConfig
//enable tun mode //enable tun mode
if (_config.TunModeItem.EnableTun) if (_config.TunModeItem.EnableTun)
{ {
string tun = Utils.GetEmbedText(Global.ClashTunYaml); var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
if (Utils.IsNotEmpty(tun)) if (Utils.IsNotEmpty(tun))
{ {
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun); var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
@@ -128,7 +128,7 @@ namespace ServiceLib.Services.CoreConfig
//Mixin //Mixin
try try
{ {
MixinContent(fileContent, node); await MixinContent(fileContent, node);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -158,20 +158,21 @@ namespace ServiceLib.Services.CoreConfig
} }
} }
private void MixinContent(Dictionary<string, object> fileContent, ProfileItem node) private async Task MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
{ {
//if (!_config.clashUIItem.enableMixinContent) if (!_config.ClashUIItem.EnableMixinContent)
//{
// return;
//}
var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
if (!File.Exists(path))
{ {
return; return;
} }
var txtFile = File.ReadAllText(Utils.GetConfigPath(Global.ClashMixinConfigFileName)); var path = Utils.GetConfigPath(Global.ClashMixinConfigFileName);
if (!File.Exists(path))
{
var mixin = EmbedUtils.GetEmbedText(Global.ClashMixinYaml);
await File.AppendAllTextAsync(path, mixin);
}
var txtFile = await File.ReadAllTextAsync(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile); var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
if (mixinContent == null) if (mixinContent == null)

View File

@@ -35,7 +35,7 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient); string result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -91,8 +91,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
var result = Utils.GetEmbedText(Global.SingboxSampleClient); var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient);
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -242,6 +242,66 @@ namespace ServiceLib.Services.CoreConfig
} }
} }
public async Task<RetResult> GenerateClientSpeedtestConfig(ProfileItem node, int port)
{
var ret = new RetResult();
try
{
if (node is not { Port: > 0 })
{
ret.Msg = ResUI.CheckServerSettings;
return ret;
}
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.xhttp))
{
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret;
}
ret.Msg = ResUI.InitialConfiguration;
var result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient);
if (Utils.IsNullOrEmpty(result))
{
ret.Msg = ResUI.FailedGetDefaultConfiguration;
return ret;
}
var singboxConfig = JsonUtils.Deserialize<SingboxConfig>(result);
if (singboxConfig == null)
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
await GenLog(singboxConfig);
await GenOutbound(node, singboxConfig.outbounds.First());
await GenMoreOutbounds(node, singboxConfig);
await GenDnsDomains(null, singboxConfig, null);
singboxConfig.route.rules.Clear();
singboxConfig.inbounds.Clear();
singboxConfig.inbounds.Add(new()
{
tag = $"{EInboundProtocol.mixed}{port}",
listen = Global.Loopback,
listen_port = port,
type = EInboundProtocol.mixed.ToString(),
});
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
ret.Data = JsonUtils.Serialize(singboxConfig);
return ret;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
}
public async Task<RetResult> GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds) public async Task<RetResult> GenerateClientMultipleLoadConfig(List<ProfileItem> selecteds)
{ {
var ret = new RetResult(); var ret = new RetResult();
@@ -255,8 +315,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient); string result = EmbedUtils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); string txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -539,14 +599,14 @@ namespace ServiceLib.Services.CoreConfig
{ {
if (_config.TunModeItem.Mtu <= 0) if (_config.TunModeItem.Mtu <= 0)
{ {
_config.TunModeItem.Mtu = Utils.ToInt(Global.TunMtus.First()); _config.TunModeItem.Mtu = Global.TunMtus.First();
} }
if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack)) if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack))
{ {
_config.TunModeItem.Stack = Global.TunStacks.First(); _config.TunModeItem.Stack = Global.TunStacks.First();
} }
var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(Utils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { }; var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(EmbedUtils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { };
tunInbound.interface_name = Utils.IsOSX() ? $"utun{new Random().Next(99)}" : "singbox_tun"; tunInbound.interface_name = Utils.IsOSX() ? $"utun{new Random().Next(99)}" : "singbox_tun";
tunInbound.mtu = _config.TunModeItem.Mtu; tunInbound.mtu = _config.TunModeItem.Mtu;
tunInbound.strict_route = _config.TunModeItem.StrictRoute; tunInbound.strict_route = _config.TunModeItem.StrictRoute;
@@ -685,7 +745,7 @@ namespace ServiceLib.Services.CoreConfig
outbound.peer_public_key = node.PublicKey; outbound.peer_public_key = node.PublicKey;
outbound.reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList(); outbound.reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList();
outbound.local_address = Utils.String2List(node.RequestHost); outbound.local_address = Utils.String2List(node.RequestHost);
outbound.mtu = Utils.ToInt(node.ShortId.IsNullOrEmpty() ? Global.TunMtus.FirstOrDefault() : node.ShortId); outbound.mtu = Utils.ToInt(node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId);
break; break;
} }
} }
@@ -867,7 +927,7 @@ namespace ServiceLib.Services.CoreConfig
//current proxy //current proxy
var outbound = singboxConfig.outbounds.First(); var outbound = singboxConfig.outbounds.First();
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
//Previous proxy //Previous proxy
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
@@ -934,7 +994,7 @@ namespace ServiceLib.Services.CoreConfig
{ {
singboxConfig.route.auto_detect_interface = true; singboxConfig.route.auto_detect_interface = true;
var tunRules = JsonUtils.Deserialize<List<Rule4Sbox>>(Utils.GetEmbedText(Global.TunSingboxRulesFileName)); var tunRules = JsonUtils.Deserialize<List<Rule4Sbox>>(EmbedUtils.GetEmbedText(Global.TunSingboxRulesFileName));
if (tunRules != null) if (tunRules != null)
{ {
singboxConfig.route.rules.AddRange(tunRules); singboxConfig.route.rules.AddRange(tunRules);
@@ -1048,7 +1108,8 @@ namespace ServiceLib.Services.CoreConfig
var countDomain = 0; var countDomain = 0;
foreach (var it in item.Domain) foreach (var it in item.Domain)
{ {
if (ParseV2Domain(it, rule1)) countDomain++; if (ParseV2Domain(it, rule1))
countDomain++;
} }
if (countDomain > 0) if (countDomain > 0)
{ {
@@ -1062,7 +1123,8 @@ namespace ServiceLib.Services.CoreConfig
var countIp = 0; var countIp = 0;
foreach (var it in item.Ip) foreach (var it in item.Ip)
{ {
if (ParseV2Address(it, rule2)) countIp++; if (ParseV2Address(it, rule2))
countIp++;
} }
if (countIp > 0) if (countIp > 0)
{ {
@@ -1148,12 +1210,14 @@ namespace ServiceLib.Services.CoreConfig
} }
else if (address.StartsWith("geoip:")) else if (address.StartsWith("geoip:"))
{ {
if (rule.geoip is null) { rule.geoip = new(); } if (rule.geoip is null)
{ rule.geoip = new(); }
rule.geoip?.Add(address.Substring(6)); rule.geoip?.Add(address.Substring(6));
} }
else else
{ {
if (rule.ip_cidr is null) { rule.ip_cidr = new(); } if (rule.ip_cidr is null)
{ rule.ip_cidr = new(); }
rule.ip_cidr?.Add(address); rule.ip_cidr?.Add(address);
} }
return true; return true;
@@ -1167,11 +1231,11 @@ namespace ServiceLib.Services.CoreConfig
var strDNS = string.Empty; var strDNS = string.Empty;
if (_config.TunModeItem.EnableTun) if (_config.TunModeItem.EnableTun)
{ {
strDNS = Utils.IsNullOrEmpty(item?.TunDNS) ? Utils.GetEmbedText(Global.TunSingboxDNSFileName) : item?.TunDNS; strDNS = Utils.IsNullOrEmpty(item?.TunDNS) ? EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName) : item?.TunDNS;
} }
else else
{ {
strDNS = Utils.IsNullOrEmpty(item?.NormalDNS) ? Utils.GetEmbedText(Global.DNSSingboxNormalFileName) : item?.NormalDNS; strDNS = Utils.IsNullOrEmpty(item?.NormalDNS) ? EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName) : item?.NormalDNS;
} }
var dns4Sbox = JsonUtils.Deserialize<Dns4Sbox>(strDNS); var dns4Sbox = JsonUtils.Deserialize<Dns4Sbox>(strDNS);
@@ -1260,7 +1324,7 @@ namespace ServiceLib.Services.CoreConfig
singboxConfig.experimental.cache_file = new CacheFile4Sbox() singboxConfig.experimental.cache_file = new CacheFile4Sbox()
{ {
enabled = true, enabled = true,
path = Utils.GetConfigPath("cache.db") path = Utils.GetBinPath("cache.db")
}; };
} }
@@ -1271,7 +1335,8 @@ namespace ServiceLib.Services.CoreConfig
{ {
static void AddRuleSets(List<string> ruleSets, List<string>? rule_set) static void AddRuleSets(List<string> ruleSets, List<string>? rule_set)
{ {
if (rule_set != null) ruleSets.AddRange(rule_set); if (rule_set != null)
ruleSets.AddRange(rule_set);
} }
var geosite = "geosite"; var geosite = "geosite";
var geoip = "geoip"; var geoip = "geoip";
@@ -1321,7 +1386,7 @@ namespace ServiceLib.Services.CoreConfig
var routing = await ConfigHandler.GetDefaultRouting(_config); var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox)) if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox))
{ {
var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox); var result = EmbedUtils.LoadResource(routing.CustomRulesetPath4Singbox);
if (Utils.IsNotEmpty(result)) if (Utils.IsNotEmpty(result))
{ {
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? []) customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
@@ -1339,7 +1404,8 @@ namespace ServiceLib.Services.CoreConfig
singboxConfig.route.rule_set = []; singboxConfig.route.rule_set = [];
foreach (var item in new HashSet<string>(ruleSets)) foreach (var item in new HashSet<string>(ruleSets))
{ {
if (Utils.IsNullOrEmpty(item)) { continue; } if (Utils.IsNullOrEmpty(item))
{ continue; }
var customRuleset = customRulesets.FirstOrDefault(t => t.tag != null && t.tag.Equals(item)); var customRuleset = customRulesets.FirstOrDefault(t => t.tag != null && t.tag.Equals(item));
if (customRuleset is null) if (customRuleset is null)
{ {

View File

@@ -1,4 +1,4 @@
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
@@ -36,7 +36,7 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
var result = Utils.GetEmbedText(Global.V2raySampleClient); var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -91,8 +91,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient); string result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); string txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -214,8 +214,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
var result = Utils.GetEmbedText(Global.V2raySampleClient); var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -353,6 +353,64 @@ namespace ServiceLib.Services.CoreConfig
} }
} }
public async Task<RetResult> GenerateClientSpeedtestConfig(ProfileItem node, int port)
{
var ret = new RetResult();
try
{
if (node is not { Port: > 0 })
{
ret.Msg = ResUI.CheckServerSettings;
return ret;
}
if (node.GetNetwork() is nameof(ETransport.quic))
{
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret;
}
var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
if (Utils.IsNullOrEmpty(result))
{
ret.Msg = ResUI.FailedGetDefaultConfiguration;
return ret;
}
var v2rayConfig = JsonUtils.Deserialize<V2rayConfig>(result);
if (v2rayConfig == null)
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
await GenLog(v2rayConfig);
await GenOutbound(node, v2rayConfig.outbounds.First());
await GenMoreOutbounds(node, v2rayConfig);
v2rayConfig.routing.rules.Clear();
v2rayConfig.inbounds.Clear();
v2rayConfig.inbounds.Add(new()
{
tag = $"{EInboundProtocol.socks}{port}",
listen = Global.Loopback,
port = port,
protocol = EInboundProtocol.socks.ToString(),
});
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
ret.Data = JsonUtils.Serialize(v2rayConfig);
return ret;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
}
#endregion public gen function #endregion public gen function
#region private gen function #region private gen function
@@ -428,7 +486,7 @@ namespace ServiceLib.Services.CoreConfig
private Inbounds4Ray GetInbound(InItem inItem, EInboundProtocol protocol, bool bSocks) private Inbounds4Ray GetInbound(InItem inItem, EInboundProtocol protocol, bool bSocks)
{ {
string result = Utils.GetEmbedText(Global.V2raySampleInbound); string result = EmbedUtils.GetEmbedText(Global.V2raySampleInbound);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
return new(); return new();
@@ -992,7 +1050,7 @@ namespace ServiceLib.Services.CoreConfig
}; };
//request Host //request Host
string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName); string request = EmbedUtils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
string[] arrHost = host.Split(','); string[] arrHost = host.Split(',');
string host2 = string.Join(",".AppendQuotes(), arrHost); string host2 = string.Join(",".AppendQuotes(), arrHost);
request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}"); request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
@@ -1028,7 +1086,7 @@ namespace ServiceLib.Services.CoreConfig
var domainStrategy4Freedom = item?.DomainStrategy4Freedom; var domainStrategy4Freedom = item?.DomainStrategy4Freedom;
if (Utils.IsNullOrEmpty(normalDNS)) if (Utils.IsNullOrEmpty(normalDNS))
{ {
normalDNS = Utils.GetEmbedText(Global.DNSV2rayNormalFileName); normalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
} }
//Outbound Freedom domainStrategy //Outbound Freedom domainStrategy
@@ -1196,7 +1254,7 @@ namespace ServiceLib.Services.CoreConfig
//current proxy //current proxy
var outbound = v2rayConfig.outbounds.First(); var outbound = v2rayConfig.outbounds.First();
var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
//Previous proxy //Previous proxy
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);

View File

@@ -1,4 +1,4 @@
using System.Diagnostics; using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Sockets; using System.Net.Sockets;
@@ -222,28 +222,29 @@ namespace ServiceLib.Services
public async Task<int> RunAvailabilityCheck(IWebProxy? webProxy) public async Task<int> RunAvailabilityCheck(IWebProxy? webProxy)
{ {
var responseTime = -1;
try try
{ {
webProxy ??= await GetWebProxy(true); webProxy ??= await GetWebProxy(true);
try
{
var config = AppHandler.Instance.Config; var config = AppHandler.Instance.Config;
var responseTime = await GetRealPingTime(config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
for (var i = 0; i < 2; i++)
{
responseTime = await GetRealPingTime(config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
if (responseTime > 0)
{
break;
}
await Task.Delay(500);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return -1;
}
return responseTime; return responseTime;
} }
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return -1;
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return -1;
}
}
public async Task<int> GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout) public async Task<int> GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout)
{ {

View File

@@ -1,4 +1,4 @@
using ReactiveUI; using System.Collections.Concurrent;
using System.Diagnostics; using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
@@ -7,17 +7,68 @@ namespace ServiceLib.Services
{ {
public class SpeedtestService public class SpeedtestService
{ {
private static readonly string _tag = "SpeedtestService";
private Config? _config; private Config? _config;
private Action<SpeedTestResult>? _updateFunc; private Action<SpeedTestResult>? _updateFunc;
private static readonly ConcurrentBag<string> _lstExitLoop = new();
private bool _exitLoop = false; public SpeedtestService(Config config, Action<SpeedTestResult> updateFunc)
private static readonly string _tag = "SpeedtestService";
public SpeedtestService(Config config, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> updateFunc)
{ {
_config = config; _config = config;
_updateFunc = updateFunc; _updateFunc = updateFunc;
}
public void RunLoop(ESpeedActionType actionType, List<ProfileItem> selecteds)
{
Task.Run(async () =>
{
await RunAsync(actionType, selecteds);
await ProfileExHandler.Instance.SaveTo();
UpdateFunc("", ResUI.SpeedtestingCompleted);
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
});
}
public void ExitLoop()
{
if (_lstExitLoop.Count > 0)
{
UpdateFunc("", ResUI.SpeedtestingStop);
_lstExitLoop.Clear();
}
}
private async Task RunAsync(ESpeedActionType actionType, List<ProfileItem> selecteds)
{
var exitLoopKey = Utils.GetGuid(false);
_lstExitLoop.Add(exitLoopKey);
var lstSelected = GetClearItem(actionType, selecteds);
switch (actionType)
{
case ESpeedActionType.Tcping:
await RunTcpingAsync(lstSelected);
break;
case ESpeedActionType.Realping:
await RunRealPingBatchAsync(lstSelected, exitLoopKey);
break;
case ESpeedActionType.Speedtest:
await RunMixedTestAsync(lstSelected, 1, true, exitLoopKey);
break;
case ESpeedActionType.Mixedtest:
await RunMixedTestAsync(lstSelected, _config.SpeedTestItem.MixedConcurrencyCount, true, exitLoopKey);
break;
}
}
private List<ServerTestItem> GetClearItem(ESpeedActionType actionType, List<ProfileItem> selecteds)
{
var lstSelected = new List<ServerTestItem>(); var lstSelected = new List<ServerTestItem>();
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
@@ -25,16 +76,19 @@ namespace ServiceLib.Services
{ {
continue; continue;
} }
if (it.Port <= 0) if (it.Port <= 0)
{ {
continue; continue;
} }
lstSelected.Add(new ServerTestItem() lstSelected.Add(new ServerTestItem()
{ {
IndexId = it.IndexId, IndexId = it.IndexId,
Address = it.Address, Address = it.Address,
Port = it.Port, Port = it.Port,
ConfigType = it.ConfigType ConfigType = it.ConfigType,
QueueNum = selecteds.IndexOf(it)
}); });
} }
@@ -46,87 +100,26 @@ namespace ServiceLib.Services
case ESpeedActionType.Tcping: case ESpeedActionType.Tcping:
case ESpeedActionType.Realping: case ESpeedActionType.Realping:
UpdateFunc(it.IndexId, ResUI.Speedtesting, ""); UpdateFunc(it.IndexId, ResUI.Speedtesting, "");
ProfileExHandler.Instance.SetTestDelay(it.IndexId, "0"); ProfileExHandler.Instance.SetTestDelay(it.IndexId, 0);
break; break;
case ESpeedActionType.Speedtest: case ESpeedActionType.Speedtest:
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingWait); UpdateFunc(it.IndexId, "", ResUI.SpeedtestingWait);
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "0"); ProfileExHandler.Instance.SetTestSpeed(it.IndexId, 0);
break; break;
case ESpeedActionType.Mixedtest: case ESpeedActionType.Mixedtest:
UpdateFunc(it.IndexId, ResUI.Speedtesting, ResUI.SpeedtestingWait); UpdateFunc(it.IndexId, ResUI.Speedtesting, ResUI.SpeedtestingWait);
ProfileExHandler.Instance.SetTestDelay(it.IndexId, "0"); ProfileExHandler.Instance.SetTestDelay(it.IndexId, 0);
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "0"); ProfileExHandler.Instance.SetTestSpeed(it.IndexId, 0);
break; break;
} }
} }
MessageBus.Current.Listen<string>(EMsgCommand.StopSpeedtest.ToString()).Subscribe(ExitLoop); return lstSelected;
Task.Run(async () => { await RunAsync(actionType, lstSelected); });
}
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 RunTcpingAsync(List<ServerTestItem> selecteds) private async Task RunTcpingAsync(List<ServerTestItem> selecteds)
{
try
{ {
List<Task> tasks = []; List<Task> tasks = [];
foreach (var it in selecteds) foreach (var it in selecteds)
@@ -139,11 +132,10 @@ namespace ServiceLib.Services
{ {
try try
{ {
var time = await GetTcpingTime(it.Address, it.Port); var responseTime = await GetTcpingTime(it.Address, it.Port);
var output = FormatOut(time, Global.DelayUnit);
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output); ProfileExHandler.Instance.SetTestDelay(it.IndexId, responseTime);
UpdateFunc(it.IndexId, output); UpdateFunc(it.IndexId, responseTime.ToString());
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -152,18 +144,52 @@ namespace ServiceLib.Services
})); }));
} }
Task.WaitAll([.. tasks]); Task.WaitAll([.. tasks]);
await Task.CompletedTask;
} }
catch (Exception ex)
private async Task RunRealPingBatchAsync(List<ServerTestItem> lstSelected, string exitLoopKey, int pageSize = 0)
{ {
Logging.SaveLog(_tag, ex); if (pageSize <= 0)
{
pageSize = lstSelected.Count < Global.SpeedTestPageSize ? lstSelected.Count : Global.SpeedTestPageSize;
} }
finally var lstTest = GetTestBatchItem(lstSelected, pageSize);
List<ServerTestItem> lstFailed = new();
foreach (var lst in lstTest)
{ {
await ProfileExHandler.Instance.SaveTo(); var ret = await RunRealPingAsync(lst, exitLoopKey);
if (ret == false)
{
lstFailed.AddRange(lst);
}
await Task.Delay(100);
}
//Retest the failed part
var pageSizeNext = pageSize / 2;
if (lstFailed.Count > 0 && pageSizeNext > 0)
{
if (_lstExitLoop.Any(p => p == exitLoopKey) == false)
{
UpdateFunc("", ResUI.SpeedtestingSkip);
return;
}
UpdateFunc("", string.Format(ResUI.SpeedtestingTestFailedPart, lstFailed.Count));
if (pageSizeNext > _config.SpeedTestItem.MixedConcurrencyCount)
{
await RunRealPingBatchAsync(lstFailed, exitLoopKey, pageSizeNext);
}
else
{
await RunMixedTestAsync(lstSelected, _config.SpeedTestItem.MixedConcurrencyCount, false, exitLoopKey);
}
} }
} }
private async Task RunRealPingAsync(List<ServerTestItem> selecteds) private async Task<bool> RunRealPingAsync(List<ServerTestItem> selecteds, string exitLoopKey)
{ {
var pid = -1; var pid = -1;
try try
@@ -171,8 +197,7 @@ namespace ServiceLib.Services
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds); pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
if (pid < 0) if (pid < 0)
{ {
UpdateFunc("", ResUI.FailedToRunCore); return false;
return;
} }
var downloadHandle = new DownloadService(); var downloadHandle = new DownloadService();
@@ -190,20 +215,7 @@ namespace ServiceLib.Services
} }
tasks.Add(Task.Run(async () => tasks.Add(Task.Run(async () =>
{ {
try await DoRealPing(downloadHandle, it);
{
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
var output = await GetRealPingTime(downloadHandle, webProxy);
ProfileExHandler.Instance.SetTestDelay(it.IndexId, output);
UpdateFunc(it.IndexId, output);
int.TryParse(output, out var delay);
it.Delay = delay;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
})); }));
} }
Task.WaitAll(tasks.ToArray()); Task.WaitAll(tasks.ToArray());
@@ -218,151 +230,100 @@ namespace ServiceLib.Services
{ {
await ProcUtils.ProcessKill(pid); await ProcUtils.ProcessKill(pid);
} }
await ProfileExHandler.Instance.SaveTo();
} }
return true;
} }
private async Task RunSpeedTestAsync(List<ServerTestItem> selecteds) private async Task RunMixedTestAsync(List<ServerTestItem> selecteds, int concurrencyCount, bool blSpeedTest, string exitLoopKey)
{ {
var pid = -1; using var concurrencySemaphore = new SemaphoreSlim(concurrencyCount);
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds); var downloadHandle = new DownloadService();
if (pid < 0) List<Task> tasks = new();
{
UpdateFunc("", ResUI.FailedToRunCore);
return;
}
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) if (_lstExitLoop.Any(p => p == exitLoopKey) == false)
{ {
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip); UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
continue; continue;
} }
if (!it.AllowTest)
{
continue;
}
if (it.ConfigType == EConfigType.Custom) if (it.ConfigType == EConfigType.Custom)
{ {
continue; continue;
} }
//if (it.delay < 0) await concurrencySemaphore.WaitAsync();
//{
// UpdateFunc(it.indexId, "", ResUI.SpeedtestingSkip); tasks.Add(Task.Run(async () =>
// continue; {
//} var pid = -1;
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1"); try
{
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(it);
if (pid > 0)
{
await Task.Delay(500);
var delay = await DoRealPing(downloadHandle, it);
if (blSpeedTest)
{
if (delay > 0)
{
await DoSpeedTest(downloadHandle, it);
}
else
{
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
}
}
}
else
{
UpdateFunc(it.IndexId, "", ResUI.FailedToRunCore);
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
finally
{
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
concurrencySemaphore.Release();
}
}));
}
Task.WaitAll(tasks.ToArray());
}
private async Task<int> DoRealPing(DownloadService downloadHandle, ServerTestItem it)
{
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
ProfileExHandler.Instance.SetTestDelay(it.IndexId, responseTime);
UpdateFunc(it.IndexId, responseTime.ToString());
return responseTime;
}
private async Task DoSpeedTest(DownloadService downloadHandle, ServerTestItem it)
{
UpdateFunc(it.IndexId, "", ResUI.Speedtesting); UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
if (item is null) continue;
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}"); var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) => await downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
{ {
decimal.TryParse(msg, out var dec); decimal.TryParse(msg, out var dec);
if (dec > 0) if (dec > 0)
{ {
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg); ProfileExHandler.Instance.SetTestSpeed(it.IndexId, dec);
} }
UpdateFunc(it.IndexId, "", msg); UpdateFunc(it.IndexId, "", msg);
}); });
} }
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
await ProfileExHandler.Instance.SaveTo();
}
private async Task RunSpeedTestMulti(List<ServerTestItem> selecteds)
{
var pid = -1;
pid = await CoreHandler.Instance.LoadCoreConfigSpeedtest(selecteds);
if (pid < 0)
{
UpdateFunc("", ResUI.FailedToRunCore);
return;
}
var url = _config.SpeedTestItem.SpeedTestUrl;
var timeout = _config.SpeedTestItem.SpeedTestTimeout;
DownloadService downloadHandle = new();
foreach (var it in selecteds)
{
if (_exitLoop)
{
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
continue;
}
if (!it.AllowTest)
{
continue;
}
if (it.ConfigType == EConfigType.Custom)
{
continue;
}
if (it.Delay < 0)
{
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
continue;
}
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, "-1");
UpdateFunc(it.IndexId, "", ResUI.Speedtesting);
var item = await AppHandler.Instance.GetProfileItem(it.IndexId);
if (item is null) continue;
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
_ = downloadHandle.DownloadDataAsync(url, webProxy, timeout, (success, msg) =>
{
decimal.TryParse(msg, out var dec);
if (dec > 0)
{
ProfileExHandler.Instance.SetTestSpeed(it.IndexId, msg);
}
UpdateFunc(it.IndexId, "", msg);
});
await Task.Delay(2000);
}
await Task.Delay((timeout + 2) * 1000);
if (pid > 0)
{
await ProcUtils.ProcessKill(pid);
}
await ProfileExHandler.Instance.SaveTo();
}
private async Task RunMixedTestAsync(List<ServerTestItem> selecteds)
{
await RunRealPingAsync(selecteds);
await Task.Delay(1000);
await RunSpeedTestMulti(selecteds);
}
private async Task<string> GetRealPingTime(DownloadService downloadHandle, IWebProxy webProxy)
{
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) private async Task<int> GetTcpingTime(string url, int port)
{ {
var responseTime = -1; var responseTime = -1;
@@ -375,18 +336,19 @@ namespace ServiceLib.Services
ipAddress = ipHostInfo.AddressList.First(); ipAddress = ipHostInfo.AddressList.First();
} }
var timer = Stopwatch.StartNew();
IPEndPoint endPoint = new(ipAddress, port); IPEndPoint endPoint = new(ipAddress, port);
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
var timer = Stopwatch.StartNew();
var result = clientSocket.BeginConnect(endPoint, null, null); var result = clientSocket.BeginConnect(endPoint, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))) if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
{
throw new TimeoutException("connect timeout (5s): " + url); throw new TimeoutException("connect timeout (5s): " + url);
clientSocket.EndConnect(result); }
timer.Stop(); timer.Stop();
responseTime = (int)timer.Elapsed.TotalMilliseconds; responseTime = (int)timer.Elapsed.TotalMilliseconds;
clientSocket.EndConnect(result);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -395,14 +357,31 @@ namespace ServiceLib.Services
return responseTime; return responseTime;
} }
private string FormatOut(object time, string unit) private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
{ {
return $"{time}"; 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());
}
return lstTest;
} }
private void UpdateFunc(string indexId, string delay, string speed = "") private void UpdateFunc(string indexId, string delay, string speed = "")
{ {
_updateFunc?.Invoke(new() { IndexId = indexId, Delay = delay, Speed = speed }); _updateFunc?.Invoke(new() { IndexId = indexId, Delay = delay, Speed = speed });
if (indexId.IsNotEmpty() && speed.IsNotEmpty())
{
ProfileExHandler.Instance.SetTestMessage(indexId, speed);
}
} }
} }
} }

View File

@@ -1,4 +1,4 @@
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
namespace ServiceLib.Services.Statistics namespace ServiceLib.Services.Statistics
@@ -21,7 +21,7 @@ namespace ServiceLib.Services.Statistics
Task.Run(Run); Task.Run(Run);
} }
private async void Init() private async Task Init()
{ {
await Task.Delay(5000); await Task.Delay(5000);
@@ -53,9 +53,9 @@ namespace ServiceLib.Services.Statistics
} }
} }
private async void Run() private async Task Run()
{ {
Init(); await Init();
while (!_exitFlag) while (!_exitFlag)
{ {
@@ -73,7 +73,7 @@ namespace ServiceLib.Services.Statistics
{ {
webSocket.Abort(); webSocket.Abort();
webSocket = null; webSocket = null;
Init(); await Init();
continue; continue;
} }
@@ -109,7 +109,8 @@ namespace ServiceLib.Services.Statistics
private void ParseOutput(string source, out ulong up, out ulong down) private void ParseOutput(string source, out ulong up, out ulong down)
{ {
up = 0; down = 0; up = 0;
down = 0;
try try
{ {
var trafficItem = JsonUtils.Deserialize<TrafficItem>(source); var trafficItem = JsonUtils.Deserialize<TrafficItem>(source);

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Services.Statistics namespace ServiceLib.Services.Statistics
{ {
public class StatisticsXrayService public class StatisticsXrayService
{ {
@@ -23,7 +23,7 @@
_exitFlag = true; _exitFlag = true;
} }
private async void Run() private async Task Run()
{ {
while (!_exitFlag) while (!_exitFlag)
{ {
@@ -63,7 +63,8 @@
foreach (string key in source.stats.outbound.Keys) foreach (string key in source.stats.outbound.Keys)
{ {
var value = source.stats.outbound[key]; var value = source.stats.outbound[key];
if (value == null) continue; if (value == null)
continue;
var state = JsonUtils.Deserialize<V2rayMetricsVarsLink>(value.ToString()); var state = JsonUtils.Deserialize<V2rayMetricsVarsLink>(value.ToString());
if (key.StartsWith(Global.ProxyTag)) if (key.StartsWith(Global.ProxyTag))

View File

@@ -237,13 +237,13 @@ namespace ServiceLib.Services
public async Task UpdateGeoFileAll(Config config, Action<bool, string> updateFunc) public async Task UpdateGeoFileAll(Config config, Action<bool, string> updateFunc)
{ {
await UpdateGeoFile("geosite", config, updateFunc); await UpdateGeoFiles(config, updateFunc);
await UpdateGeoFile("geoip", config, updateFunc); await UpdateOtherFiles(config, updateFunc);
await UpdateSrsFileAll(config, updateFunc); await UpdateSrsFileAll(config, updateFunc);
_updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo")); _updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
} }
public async Task RunAvailabilityCheck(Action<bool, string> updateFunc) public async Task<string> RunAvailabilityCheck()
{ {
var downloadHandle = new DownloadService(); var downloadHandle = new DownloadService();
var time = await downloadHandle.RunAvailabilityCheck(null); var time = await downloadHandle.RunAvailabilityCheck(null);
@@ -255,7 +255,7 @@ namespace ServiceLib.Services
ip = $"({ipInfo?.country_code}) {ipInfo?.ip}"; ip = $"({ipInfo?.country_code}) {ipInfo?.ip}";
} }
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time, ip)); return string.Format(ResUI.TestMeOutput, time, ip);
} }
#region CheckUpdate private #region CheckUpdate private
@@ -368,6 +368,7 @@ namespace ServiceLib.Services
try try
{ {
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type);
var coreUrl = await GetUrlFromCore(coreInfo) ?? string.Empty;
SemanticVersion curVersion; SemanticVersion curVersion;
string message; string message;
string? url; string? url;
@@ -379,28 +380,28 @@ namespace ServiceLib.Services
{ {
curVersion = await GetCoreVersion(type); curVersion = await GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v")); message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v")); url = string.Format(coreUrl, version.ToVersionString("v"));
break; break;
} }
case ECoreType.mihomo: case ECoreType.mihomo:
{ {
curVersion = await GetCoreVersion(type); curVersion = await GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion); message = string.Format(ResUI.IsLatestCore, type, curVersion);
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v")); url = string.Format(coreUrl, version.ToVersionString("v"));
break; break;
} }
case ECoreType.sing_box: case ECoreType.sing_box:
{ {
curVersion = await GetCoreVersion(type); curVersion = await GetCoreVersion(type);
message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v")); message = string.Format(ResUI.IsLatestCore, type, curVersion.ToVersionString("v"));
url = string.Format(GetUrlFromCore(coreInfo), version.ToVersionString("v"), version); url = string.Format(coreUrl, version.ToVersionString("v"), version);
break; break;
} }
case ECoreType.v2rayN: case ECoreType.v2rayN:
{ {
curVersion = new SemanticVersion(Utils.GetVersionInfo()); curVersion = new SemanticVersion(Utils.GetVersionInfo());
message = string.Format(ResUI.IsLatestN, type, curVersion); message = string.Format(ResUI.IsLatestN, type, curVersion);
url = string.Format(GetUrlFromCore(coreInfo), version); url = string.Format(coreUrl, version);
break; break;
} }
default: default:
@@ -422,25 +423,36 @@ namespace ServiceLib.Services
} }
} }
private string? GetUrlFromCore(CoreInfo? coreInfo) private async Task<string?> GetUrlFromCore(CoreInfo? coreInfo)
{ {
if (Utils.IsWindows()) if (Utils.IsWindows())
{ {
//Check for standalone windows .Net version var url = RuntimeInformation.ProcessArchitecture switch
if (coreInfo?.CoreType == ECoreType.v2rayN
&& File.Exists(Path.Combine(Utils.StartupPath(), "wpfgfx_cor3.dll"))
&& File.Exists(Path.Combine(Utils.StartupPath(), "D3DCompiler_47_cor3.dll"))
)
{
return coreInfo?.DownloadUrlWin64?.Replace(".zip", "-SelfContained.zip");
}
return RuntimeInformation.ProcessArchitecture switch
{ {
Architecture.Arm64 => coreInfo?.DownloadUrlWinArm64, Architecture.Arm64 => coreInfo?.DownloadUrlWinArm64,
Architecture.X64 => coreInfo?.DownloadUrlWin64, Architecture.X64 => coreInfo?.DownloadUrlWin64,
_ => null, _ => null,
}; };
if (coreInfo?.CoreType != ECoreType.v2rayN)
{
return url;
}
//Check for standalone windows .Net version
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "wpfgfx_cor3.dll"))
&& File.Exists(Path.Combine(Utils.GetBaseDirectory(), "D3DCompiler_47_cor3.dll")))
{
return url?.Replace(".zip", "-SelfContained.zip");
}
//Check for avalonia desktop windows version
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "libHarfBuzzSharp.dll")))
{
return url?.Replace(".zip", "-desktop.zip");
}
return url;
} }
else if (Utils.IsLinux()) else if (Utils.IsLinux())
{ {
@@ -460,14 +472,14 @@ namespace ServiceLib.Services
_ => null, _ => null,
}; };
} }
return null; return await Task.FromResult("");
} }
#endregion CheckUpdate private #endregion CheckUpdate private
#region Geo private #region Geo private
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> updateFunc) private async Task UpdateGeoFiles(Config config, Action<bool, string> updateFunc)
{ {
_updateFunc = updateFunc; _updateFunc = updateFunc;
@@ -475,12 +487,29 @@ namespace ServiceLib.Services
? Global.GeoUrl ? Global.GeoUrl
: config.ConstItem.GeoSourceUrl; : config.ConstItem.GeoSourceUrl;
List<string> files = ["geosite", "geoip"];
foreach (var geoName in files)
{
var fileName = $"{geoName}.dat"; var fileName = $"{geoName}.dat";
var targetPath = Utils.GetBinPath($"{fileName}"); var targetPath = Utils.GetBinPath($"{fileName}");
var url = string.Format(geoUrl, geoName); var url = string.Format(geoUrl, geoName);
await DownloadGeoFile(url, fileName, targetPath, updateFunc); await DownloadGeoFile(url, fileName, targetPath, updateFunc);
} }
}
private async Task UpdateOtherFiles(Config config, Action<bool, string> updateFunc)
{
_updateFunc = updateFunc;
foreach (var url in Global.OtherGeoUrls)
{
var fileName = Path.GetFileName(url);
var targetPath = Utils.GetBinPath($"{fileName}");
await DownloadGeoFile(url, fileName, targetPath, updateFunc);
}
}
private async Task UpdateSrsFileAll(Config config, Action<bool, string> updateFunc) private async Task UpdateSrsFileAll(Config config, Action<bool, string> updateFunc)
{ {

View File

@@ -1,6 +1,6 @@
using System.Reactive;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System.Reactive;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {

View File

@@ -1,6 +1,6 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive; using System.Reactive;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {

View File

@@ -1,7 +1,7 @@
using ReactiveUI; using System.Reactive;
using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -173,7 +173,7 @@ namespace ServiceLib.ViewModels
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}"); var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs); var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs);
FileManager.CopyDirectory(configDir, configDirTemp, false, "cache.db"); FileManager.CopyDirectory(configDir, configDirTemp, false, true, "");
var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName); var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName);
Directory.Delete(configDirZipTemp, true); Directory.Delete(configDirZipTemp, true);
return await Task.FromResult(ret); return await Task.FromResult(ret);

View File

@@ -1,10 +1,10 @@
using DynamicData; using System.Reactive;
using System.Runtime.InteropServices;
using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive;
using System.Runtime.InteropServices;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -46,10 +46,14 @@ namespace ServiceLib.ViewModels
if (RuntimeInformation.ProcessArchitecture != Architecture.X86) if (RuntimeInformation.ProcessArchitecture != Architecture.X86)
{ {
_checkUpdateModel.Add(GetCheckUpdateModel(_v2rayN)); _checkUpdateModel.Add(GetCheckUpdateModel(_v2rayN));
//Not Windows and under Win10
if (!(Utils.IsWindows() && Environment.OSVersion.Version.Major < 10))
{
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.Xray.ToString())); _checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.Xray.ToString()));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.mihomo.ToString())); _checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.mihomo.ToString()));
_checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.sing_box.ToString())); _checkUpdateModel.Add(GetCheckUpdateModel(ECoreType.sing_box.ToString()));
} }
}
_checkUpdateModel.Add(GetCheckUpdateModel(_geo)); _checkUpdateModel.Add(GetCheckUpdateModel(_geo));
} }
@@ -79,7 +83,8 @@ namespace ServiceLib.ViewModels
for (var k = _checkUpdateModel.Count - 1; k >= 0; k--) for (var k = _checkUpdateModel.Count - 1; k >= 0; k--)
{ {
var item = _checkUpdateModel[k]; var item = _checkUpdateModel[k];
if (item.IsSelected != true) continue; if (item.IsSelected != true)
continue;
UpdateView(item.CoreType, "..."); UpdateView(item.CoreType, "...");
if (item.CoreType == _geo) if (item.CoreType == _geo)
@@ -248,7 +253,7 @@ namespace ServiceLib.ViewModels
{ {
foreach (var subDir in dir.GetDirectories()) foreach (var subDir in dir.GetDirectories())
{ {
FileManager.CopyDirectory(subDir.FullName, toPath, false, null); FileManager.CopyDirectory(subDir.FullName, toPath, false, true);
subDir.Delete(true); subDir.Delete(true);
} }
} }
@@ -293,7 +298,8 @@ namespace ServiceLib.ViewModels
public void UpdateViewResult(CheckUpdateModel model) public void UpdateViewResult(CheckUpdateModel model)
{ {
var found = _checkUpdateModel.FirstOrDefault(t => t.CoreType == model.CoreType); var found = _checkUpdateModel.FirstOrDefault(t => t.CoreType == model.CoreType);
if (found == null) return; if (found == null)
return;
var itemCopy = JsonUtils.DeepCopy(found); var itemCopy = JsonUtils.DeepCopy(found);
itemCopy.Remarks = model.Remarks; itemCopy.Remarks = model.Remarks;
_checkUpdateModel.Replace(found, itemCopy); _checkUpdateModel.Replace(found, itemCopy);

View File

@@ -1,9 +1,9 @@
using System.Reactive;
using System.Reactive.Linq;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System.Reactive;
using System.Reactive.Linq;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -115,7 +115,8 @@ namespace ServiceLib.ViewModels
lstModel.Add(model); lstModel.Add(model);
} }
if (lstModel.Count <= 0) { return; } if (lstModel.Count <= 0)
{ return; }
_connectionItems.AddRange(lstModel); _connectionItems.AddRange(lstModel);
} }

View File

@@ -1,9 +1,9 @@
using System.Reactive;
using System.Reactive.Linq;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System.Reactive;
using System.Reactive.Linq;
using static ServiceLib.Models.ClashProviders; using static ServiceLib.Models.ClashProviders;
using static ServiceLib.Models.ClashProxies; using static ServiceLib.Models.ClashProxies;

View File

@@ -1,6 +1,6 @@
using System.Reactive;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System.Reactive;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -31,14 +31,14 @@ namespace ServiceLib.ViewModels
ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () => ImportDefConfig4V2rayCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
normalDNS = Utils.GetEmbedText(Global.DNSV2rayNormalFileName); normalDNS = EmbedUtils.GetEmbedText(Global.DNSV2rayNormalFileName);
await Task.CompletedTask; await Task.CompletedTask;
}); });
ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () => ImportDefConfig4SingboxCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
normalDNS2 = Utils.GetEmbedText(Global.DNSSingboxNormalFileName); normalDNS2 = EmbedUtils.GetEmbedText(Global.DNSSingboxNormalFileName);
tunDNS2 = Utils.GetEmbedText(Global.TunSingboxDNSFileName); tunDNS2 = EmbedUtils.GetEmbedText(Global.TunSingboxDNSFileName);
await Task.CompletedTask; await Task.CompletedTask;
}); });

View File

@@ -0,0 +1,65 @@
using System.Reactive;
using ReactiveUI;
namespace ServiceLib.ViewModels
{
public class GlobalHotkeySettingViewModel : MyReactiveObject
{
private readonly List<KeyEventItem> _globalHotkeys;
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
public GlobalHotkeySettingViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
{
_config = AppHandler.Instance.Config;
_updateView = updateView;
_globalHotkeys = JsonUtils.DeepCopy(_config.GlobalHotkeys);
SaveCmd = ReactiveCommand.CreateFromTask(async () =>
{
await SaveSettingAsync();
});
}
public KeyEventItem GetKeyEventItem(EGlobalHotkey eg)
{
var item = _globalHotkeys.FirstOrDefault((it) => it.EGlobalHotkey == eg);
if (item != null)
{
return item;
}
item = new()
{
EGlobalHotkey = eg,
Control = false,
Alt = false,
Shift = false,
KeyCode = null
};
_globalHotkeys.Add(item);
return item;
}
public void ResetKeyEventItem()
{
_globalHotkeys.Clear();
}
private async Task SaveSettingAsync()
{
_config.GlobalHotkeys = _globalHotkeys;
if (await ConfigHandler.SaveConfig(_config) == 0)
{
_updateView?.Invoke(EViewAction.CloseWindow, null);
}
else
{
NoticeHandler.Instance.Enqueue(ResUI.OperationFailed);
}
}
}
}

View File

@@ -1,7 +1,7 @@
using System.Reactive;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -287,14 +287,15 @@ namespace ServiceLib.ViewModels
try try
{ {
Logging.SaveLog("MyAppExitAsync Begin"); Logging.SaveLog("MyAppExitAsync Begin");
await SysProxyHandler.UpdateSysProxy(_config, true);
MessageBus.Current.SendMessage("", EMsgCommand.AppExit.ToString()); MessageBus.Current.SendMessage("", EMsgCommand.AppExit.ToString());
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
await SysProxyHandler.UpdateSysProxy(_config, true);
await ProfileExHandler.Instance.SaveTo(); await ProfileExHandler.Instance.SaveTo();
await StatisticsHandler.Instance.SaveTo(); await StatisticsHandler.Instance.SaveTo();
StatisticsHandler.Instance.Close();
await CoreHandler.Instance.CoreStop(); await CoreHandler.Instance.CoreStop();
StatisticsHandler.Instance.Close();
Logging.SaveLog("MyAppExitAsync End"); Logging.SaveLog("MyAppExitAsync End");
} }
@@ -570,7 +571,8 @@ namespace ServiceLib.ViewModels
{ {
Locator.Current.GetService<ClashProxiesViewModel>()?.ProxiesReload(); Locator.Current.GetService<ClashProxiesViewModel>()?.ProxiesReload();
} }
else { TabMainSelectedIndex = 0; } else
{ TabMainSelectedIndex = 0; }
} }
private async Task LoadCore() private async Task LoadCore()

View File

@@ -1,7 +1,7 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {

View File

@@ -1,6 +1,6 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive; using System.Reactive;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -63,7 +63,7 @@ namespace ServiceLib.ViewModels
[Reactive] public int SpeedTestTimeout { get; set; } [Reactive] public int SpeedTestTimeout { get; set; }
[Reactive] public string SpeedTestUrl { get; set; } [Reactive] public string SpeedTestUrl { get; set; }
[Reactive] public string SpeedPingTestUrl { get; set; } [Reactive] public string SpeedPingTestUrl { get; set; }
[Reactive] public int SpeedTestPageSize { get; set; } [Reactive] public int MixedConcurrencyCount { get; set; }
[Reactive] public bool EnableHWA { get; set; } [Reactive] public bool EnableHWA { get; set; }
[Reactive] public string SubConvertUrl { get; set; } [Reactive] public string SubConvertUrl { get; set; }
[Reactive] public int MainGirdOrientation { get; set; } [Reactive] public int MainGirdOrientation { get; set; }
@@ -178,7 +178,7 @@ namespace ServiceLib.ViewModels
CurrentFontFamily = _config.UiItem.CurrentFontFamily; CurrentFontFamily = _config.UiItem.CurrentFontFamily;
SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout; SpeedTestTimeout = _config.SpeedTestItem.SpeedTestTimeout;
SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl; SpeedTestUrl = _config.SpeedTestItem.SpeedTestUrl;
SpeedTestPageSize = _config.SpeedTestItem.SpeedTestPageSize; MixedConcurrencyCount = _config.SpeedTestItem.MixedConcurrencyCount;
SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl; SpeedPingTestUrl = _config.SpeedTestItem.SpeedPingTestUrl;
EnableHWA = _config.GuiItem.EnableHWA; EnableHWA = _config.GuiItem.EnableHWA;
SubConvertUrl = _config.ConstItem.SubConvertUrl; SubConvertUrl = _config.ConstItem.SubConvertUrl;
@@ -332,7 +332,7 @@ namespace ServiceLib.ViewModels
_config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit; _config.GuiItem.TrayMenuServersLimit = TrayMenuServersLimit;
_config.UiItem.CurrentFontFamily = CurrentFontFamily; _config.UiItem.CurrentFontFamily = CurrentFontFamily;
_config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout; _config.SpeedTestItem.SpeedTestTimeout = SpeedTestTimeout;
_config.SpeedTestItem.SpeedTestPageSize = SpeedTestPageSize; _config.SpeedTestItem.MixedConcurrencyCount = MixedConcurrencyCount;
_config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl; _config.SpeedTestItem.SpeedTestUrl = SpeedTestUrl;
_config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl; _config.SpeedTestItem.SpeedPingTestUrl = SpeedPingTestUrl;
_config.GuiItem.EnableHWA = EnableHWA; _config.GuiItem.EnableHWA = EnableHWA;

View File

@@ -1,11 +1,11 @@
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -16,6 +16,7 @@ namespace ServiceLib.ViewModels
private List<ProfileItem> _lstProfile; private List<ProfileItem> _lstProfile;
private string _serverFilter = string.Empty; private string _serverFilter = string.Empty;
private Dictionary<string, bool> _dicHeaderSort = new(); private Dictionary<string, bool> _dicHeaderSort = new();
private SpeedtestService? _speedtestService;
#endregion private prop #endregion private prop
@@ -78,6 +79,7 @@ namespace ServiceLib.ViewModels
public ReactiveCommand<Unit, Unit> RealPingServerCmd { get; } public ReactiveCommand<Unit, Unit> RealPingServerCmd { get; }
public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; } public ReactiveCommand<Unit, Unit> SpeedServerCmd { get; }
public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; } public ReactiveCommand<Unit, Unit> SortServerResultCmd { get; }
public ReactiveCommand<Unit, Unit> RemoveInvalidServerResultCmd { get; }
//servers export //servers export
public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; } public ReactiveCommand<Unit, Unit> Export2ClientConfigCmd { get; }
@@ -196,6 +198,10 @@ namespace ServiceLib.ViewModels
{ {
await SortServer(EServerColName.DelayVal.ToString()); await SortServer(EServerColName.DelayVal.ToString());
}); });
RemoveInvalidServerResultCmd = ReactiveCommand.CreateFromTask(async () =>
{
await RemoveInvalidServerResult();
});
//servers export //servers export
Export2ClientConfigCmd = ReactiveCommand.CreateFromTask(async () => Export2ClientConfigCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
@@ -259,11 +265,6 @@ namespace ServiceLib.ViewModels
Locator.Current.GetService<MainWindowViewModel>()?.Reload(); Locator.Current.GetService<MainWindowViewModel>()?.Reload();
} }
private void UpdateSpeedtestHandler(SpeedTestResult result)
{
_updateView?.Invoke(EViewAction.DispatcherSpeedTest, result);
}
public void SetSpeedTestResult(SpeedTestResult result) public void SetSpeedTestResult(SpeedTestResult result)
{ {
if (Utils.IsNullOrEmpty(result.IndexId)) if (Utils.IsNullOrEmpty(result.IndexId))
@@ -272,28 +273,30 @@ namespace ServiceLib.ViewModels
NoticeHandler.Instance.Enqueue(result.Delay); NoticeHandler.Instance.Enqueue(result.Delay);
return; return;
} }
var item = _profileItems.Where(it => it.IndexId == result.IndexId).FirstOrDefault(); var item = _profileItems.FirstOrDefault(it => it.IndexId == result.IndexId);
if (item != null) if (item == null)
{ {
return;
}
if (Utils.IsNotEmpty(result.Delay)) if (Utils.IsNotEmpty(result.Delay))
{ {
int.TryParse(result.Delay, out int temp); int.TryParse(result.Delay, out var temp);
item.Delay = temp; item.Delay = temp;
item.DelayVal = $"{result.Delay} {Global.DelayUnit}"; item.DelayVal = result.Delay ?? string.Empty;
} }
if (Utils.IsNotEmpty(result.Speed)) if (Utils.IsNotEmpty(result.Speed))
{ {
item.SpeedVal = $"{result.Speed} {Global.SpeedUnit}"; item.SpeedVal = result.Speed ?? string.Empty;
} }
_profileItems.Replace(item, JsonUtils.DeepCopy(item)); _profileItems.Replace(item, JsonUtils.DeepCopy(item));
} }
}
public void UpdateStatistics(ServerSpeedItem update) public void UpdateStatistics(ServerSpeedItem update)
{ {
try try
{ {
var item = _profileItems.Where(it => it.IndexId == update.IndexId).FirstOrDefault(); var item = _profileItems.FirstOrDefault(it => it.IndexId == update.IndexId);
if (item != null) if (item != null)
{ {
item.TodayDown = Utils.HumanFy(update.TodayDown); item.TodayDown = Utils.HumanFy(update.TodayDown);
@@ -425,10 +428,11 @@ namespace ServiceLib.ViewModels
Subid = t.Subid, Subid = t.Subid,
SubRemarks = t.SubRemarks, SubRemarks = t.SubRemarks,
IsActive = t.IndexId == _config.IndexId, IsActive = t.IndexId == _config.IndexId,
Sort = t33 == null ? 0 : t33.Sort, Sort = t33?.Sort ?? 0,
Delay = t33 == null ? 0 : t33.Delay, Delay = t33?.Delay ?? 0,
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay} {Global.DelayUnit}" : string.Empty, Speed = t33?.Speed ?? 0,
SpeedVal = t33?.Speed != 0 ? $"{t33?.Speed} {Global.SpeedUnit}" : string.Empty, DelayVal = t33?.Delay != 0 ? $"{t33?.Delay}" : string.Empty,
SpeedVal = t33?.Speed > 0 ? $"{t33?.Speed}" : t33?.Message ?? string.Empty,
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown), TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp), TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown), TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
@@ -516,7 +520,7 @@ namespace ServiceLib.ViewModels
} }
var exists = lstSelecteds.Exists(t => t.IndexId == _config.IndexId); var exists = lstSelecteds.Exists(t => t.IndexId == _config.IndexId);
await ConfigHandler.RemoveServer(_config, lstSelecteds); await ConfigHandler.RemoveServers(_config, lstSelecteds);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
if (lstSelecteds.Count == _profileItems.Count) if (lstSelecteds.Count == _profileItems.Count)
{ {
@@ -660,6 +664,13 @@ namespace ServiceLib.ViewModels
RefreshServers(); RefreshServers();
} }
public async Task RemoveInvalidServerResult()
{
var count = await ConfigHandler.RemoveInvalidServerResult(_config, _config.SubIndexId);
RefreshServers();
NoticeHandler.Instance.Enqueue(string.Format(ResUI.RemoveInvalidServerResultTip, count));
}
//move server //move server
private async Task MoveToGroup(bool c) private async Task MoveToGroup(bool c)
{ {
@@ -726,14 +737,14 @@ namespace ServiceLib.ViewModels
{ {
return; return;
} }
//ClearTestResult();
_ = new SpeedtestService(_config, lstSelecteds, actionType, UpdateSpeedtestHandler); _speedtestService ??= new SpeedtestService(_config, (SpeedTestResult result) => _updateView?.Invoke(EViewAction.DispatcherSpeedTest, result));
_speedtestService?.RunLoop(actionType, lstSelecteds);
} }
public void ServerSpeedtestStop() public void ServerSpeedtestStop()
{ {
MessageBus.Current.SendMessage("", EMsgCommand.StopSpeedtest.ToString()); _speedtestService?.ExitLoop();
} }
private async Task Export2ClientConfigAsync(bool blClipboard) private async Task Export2ClientConfigAsync(bool blClipboard)

View File

@@ -1,6 +1,6 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive; using System.Reactive;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {

View File

@@ -1,9 +1,9 @@
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive; using System.Reactive;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -257,7 +257,7 @@ namespace ServiceLib.ViewModels
return; return;
} }
var result = Utils.LoadResource(fileName); var result = EmbedUtils.LoadResource(fileName);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
return; return;

View File

@@ -1,7 +1,7 @@
using DynamicData.Binding; using System.Reactive;
using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System.Reactive;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {

View File

@@ -1,9 +1,9 @@
using DynamicData.Binding; using System.Reactive;
using System.Text;
using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive;
using System.Text;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {
@@ -60,6 +60,9 @@ namespace ServiceLib.ViewModels
[Reactive] [Reactive]
public int SystemProxySelected { get; set; } public int SystemProxySelected { get; set; }
[Reactive]
public bool BlSystemProxyPacVisible { get; set; }
#endregion System Proxy #endregion System Proxy
#region UI #region UI
@@ -96,6 +99,7 @@ namespace ServiceLib.ViewModels
SelectedRouting = new(); SelectedRouting = new();
SelectedServer = new(); SelectedServer = new();
RunningServerToolTipText = "-"; RunningServerToolTipText = "-";
BlSystemProxyPacVisible = Utils.IsWindows();
if (_config.TunModeItem.EnableTun && AllowEnableTun()) if (_config.TunModeItem.EnableTun && AllowEnableTun())
{ {
@@ -225,19 +229,22 @@ namespace ServiceLib.ViewModels
private async Task AddServerViaClipboard() private async Task AddServerViaClipboard()
{ {
var service = Locator.Current.GetService<MainWindowViewModel>(); var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null) await service.AddServerViaClipboardAsync(null); if (service != null)
await service.AddServerViaClipboardAsync(null);
} }
private async Task AddServerViaScan() private async Task AddServerViaScan()
{ {
var service = Locator.Current.GetService<MainWindowViewModel>(); var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null) await service.AddServerViaScanAsync(); if (service != null)
await service.AddServerViaScanAsync();
} }
private async Task UpdateSubscriptionProcess(bool blProxy) private async Task UpdateSubscriptionProcess(bool blProxy)
{ {
var service = Locator.Current.GetService<MainWindowViewModel>(); var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null) await service.UpdateSubscriptionProcess("", blProxy); if (service != null)
await service.UpdateSubscriptionProcess("", blProxy);
} }
public async Task RefreshServersBiz() public async Task RefreshServersBiz()
@@ -308,11 +315,13 @@ namespace ServiceLib.ViewModels
{ {
return; return;
} }
await (new UpdateService()).RunAvailabilityCheck(async (bool success, string msg) =>
{ _updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
var msg = await (new UpdateService()).RunAvailabilityCheck();
NoticeHandler.Instance.SendMessageEx(msg); NoticeHandler.Instance.SendMessageEx(msg);
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg); _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
});
} }
public void TestServerAvailabilityResult(string msg) public void TestServerAvailabilityResult(string msg)

View File

@@ -1,6 +1,6 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System.Reactive; using System.Reactive;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ServiceLib.ViewModels namespace ServiceLib.ViewModels
{ {

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