Compare commits

...

449 Commits

Author SHA1 Message Date
2dust
d1e6898290 up 7.10.5 2025-03-17 11:07:31 +08:00
2dust
8597332b21 Fixed warnings 2025-03-17 11:07:01 +08:00
2dust
7cc42ae249 Simply check the file hash value and delete the old pac file 2025-03-17 11:05:04 +08:00
Wydy
e054d4487d Update pac (#6924) 2025-03-17 09:06:21 +08:00
2dust
6ef36f521d Optimize and improve code 2025-03-16 15:48:42 +08:00
2dust
a02a122dd1 Update proxy_set_linux_sh
https://github.com/2dust/v2rayN/issues/6886
2025-03-16 11:01:23 +08:00
2dust
701138617c Update Directory.Packages.props 2025-03-16 10:56:33 +08:00
Avery Lynn
d0e2cc9442 Fix server deduplicaiton failure (#6900)
- Add a local method AreEquel to compare string values, return TRUE when compare between 'null' and 'string.Emtpy'
2025-03-13 20:11:10 +08:00
DHR60
d561f10edc Modify default fallback load balancing rule (#6889)
* Modify default fallback load balancing rule

* Refine default fallback load balancing rule based on domain strategy
2025-03-12 18:36:51 +08:00
2dust
2df412476a If it is a Windows WinGet installation, the configuration file is stored in the user directory
https://github.com/2dust/v2rayN/issues/6803
2025-03-09 19:04:49 +08:00
2dust
e6011cfede AI-optimized code 2025-03-07 12:11:19 +08:00
2dust
bcf43e2928 Enhanced subscription customization configuration
https://github.com/2dust/v2rayN/issues/6875
2025-03-07 11:37:01 +08:00
2dust
3f0f895424 up 7.10.4 2025-03-06 17:35:10 +08:00
2dust
07a3bdc618 AI-optimized code 2025-03-06 16:36:39 +08:00
2dust
7e348c196e AI-optimized code 2025-03-06 14:53:25 +08:00
2dust
51e5885e76 AI-optimized code 2025-03-06 14:42:21 +08:00
2dust
50d7912f62 AI-optimized code 2025-03-06 14:34:31 +08:00
2dust
3869148fc8 AI-optimized code 2025-03-06 14:30:02 +08:00
2dust
a0af4fb30c Update DownloadService.cs
AI-optimized code
2025-03-06 14:08:38 +08:00
2dust
c374b8565b Update SpeedtestService.cs
AI-optimized code
2025-03-06 14:08:29 +08:00
2dust
7e8b405555 AI-optimized code 2025-03-06 12:21:21 +08:00
2dust
c3439c5abe AI-optimized code 2025-03-06 11:10:55 +08:00
2dust
d4a8787356 AI-optimized code 2025-03-06 10:57:39 +08:00
2dust
23b27575a0 AI-optimized code 2025-03-06 10:48:18 +08:00
2dust
8d8a887c42 Update HttpClientHelper.cs
AI-optimized code
2025-03-06 10:47:57 +08:00
2dust
1229c967ba Update SemanticVersion.cs
AI-optimized code
2025-03-06 10:47:31 +08:00
2dust
d35f65f86d Update Utils.cs
AI-optimized code
2025-03-06 10:47:06 +08:00
2dust
0a8ce0f961 Update ProxySettingWindows.cs
AI-optimized code
2025-03-06 10:46:50 +08:00
2dust
8092481d26 Update Job.cs
AI-optimized code
2025-03-06 10:46:41 +08:00
2dust
764014e49a Replace all Utils.ToInt(variable) with variable.ToInt() 2025-03-05 20:26:26 +08:00
2dust
71cc6d7a88 Replace all Utils.IsNullOrEmpty(variable) with variable.IsNullOrEmpty() 2025-03-05 19:44:49 +08:00
2dust
f3af831cf2 Replace all Utils.IsNotEmpty(variable) with variable.IsNotEmpty() 2025-03-05 16:42:43 +08:00
2dust
78fde575d7 up 7.10.3 2025-03-04 17:03:26 +08:00
2dust
6e5af34877 Revert "If the update fails during the upgrade, the update will be retried."
This reverts commit 9748fbb076.
2025-03-04 17:02:05 +08:00
2dust
8d1853e991 up 7.10.2 2025-03-04 15:11:05 +08:00
DHR60
859299c712 Add kcp DNS masquerade support (#6852)
* Add kcp DNS masquerade support

* Update V2rayConfig.cs

* Update CoreConfigV2rayService.cs

---------

Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
2025-03-04 10:32:07 +08:00
2dust
7fbb0013b0 Optimizing Task Code 2025-03-03 16:57:55 +08:00
2dust
837cfbd03b Optimize UI prompts 2025-03-03 14:36:30 +08:00
2dust
cdc5d72cfa Update CoreConfigSingboxService.cs 2025-03-03 14:36:01 +08:00
DHR60
8dcf5c5b90 Add Hy2 Port hopping URI support (#6848) 2025-03-03 14:11:53 +08:00
2dust
67fe6ac3d8 Optimizing Task Code, add unified processing of scheduled tasks 2025-03-03 12:20:58 +08:00
2dust
438eaba4d5 up 7.10.1 2025-03-02 10:30:08 +08:00
2dust
3c8baa99d5 Update Directory.Packages.props 2025-03-02 10:29:43 +08:00
2dust
e70658f311 Add Hy2 Port hopping for sing-box 1.11+
https://github.com/2dust/v2rayN/issues/6772
2025-03-01 21:13:37 +08:00
2dust
2dd10cf5a1 Optimize QrcodeView 2025-03-01 19:56:52 +08:00
2dust
96781a784b git submodule update --remote 2025-03-01 15:29:54 +08:00
2dust
9748fbb076 If the update fails during the upgrade, the update will be retried. 2025-03-01 14:23:43 +08:00
2dust
aa5e4378ab Update AutoStartupHandler.cs 2025-03-01 14:14:07 +08:00
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
2dust
43c95422b7 up 7.6.2 2025-01-15 19:49:14 +08:00
esmaiel777
2662243641 Update dns_singbox_normal (#6511) 2025-01-15 19:47:45 +08:00
esmaiel777
060a35e091 Update tun_singbox_dns (#6510) 2025-01-15 19:47:34 +08:00
2dust
de1132c2df Added option to display real-time speed 2025-01-15 19:45:53 +08:00
2dust
f19edc9370 Improvements and Adjustments
InitCoreInfo()
2025-01-15 17:31:13 +08:00
2dust
f1601c463b Improvements and Adjustments
await Task.CompletedTask;
return await Task.FromResult(0);
2025-01-15 17:26:15 +08:00
2dust
77b15cd530 Add a prompt for not setting a password when open Tun on macos 2025-01-15 11:02:49 +08:00
2dust
a6479fe0d0 Update build-windows.yml 2025-01-14 18:15:45 +08:00
2dust
4ad4e27dc1 Improve reload function 2025-01-14 17:05:13 +08:00
2dust
7370684985 Improve delete expired files 2025-01-14 17:04:43 +08:00
2dust
5ae58e6a98 Improve reload function 2025-01-14 14:49:17 +08:00
2dust
780ccb1932 Improved ProfileItemsEx 2025-01-14 11:48:02 +08:00
2dust
6b4076be10 up 7.6.1 2025-01-12 19:36:19 +08:00
alphax-hue3682
d7a04a15ae Update Persian translate (#6487) 2025-01-12 19:33:57 +08:00
2dust
2ae43f8bdb Revert "Remove rules custom Icon"
This reverts commit d3ebc17a10.
2025-01-12 19:33:23 +08:00
2dust
d3ebc17a10 Remove rules custom Icon 2025-01-12 14:35:59 +08:00
2dust
7a8680711e Improvements and Adjustments 2025-01-12 14:30:49 +08:00
2dust
649e89e7af Added Copy Terminal proxy command to clipboard in tray menu
https://github.com/2dust/v2rayN/issues/6482
2025-01-12 11:07:34 +08:00
2dust
cb94d64395 Bug fix 2025-01-11 19:35:32 +08:00
2dust
2440dc2440 Remove deprecated DefIEProxyExceptions 2025-01-11 19:34:04 +08:00
Little丶Dreams
364a24c580 CloneServerStatItem 时检查indexId和toIndexId是否相同 (#6478) 2025-01-11 14:44:09 +08:00
2dust
8f3e0dbd82 up 7.6.0 2025-01-11 11:48:57 +08:00
alphax-hue3682
596234df26 Update Persian translate (#6465)
* Update ResUI.fa-Ir.resx

e0ae101ff4

* Update ResUI.fa-Ir.resx
2025-01-11 11:30:06 +08:00
2dust
c38aec50dc Delete unused resources 2025-01-11 11:28:35 +08:00
2dust
40915b5f98 Adjust theme options for windows 2025-01-11 11:23:40 +08:00
2dust
a176613119 Bug fix for ProcUtils 2025-01-11 10:44:34 +08:00
2dust
6c6de1ae7f Improvements and Adjustments 2025-01-10 20:12:42 +08:00
2dust
edbd168dcf Add theme options for desktop 2025-01-10 15:53:06 +08:00
2dust
127858d582 Adjust UI for desktop 2025-01-10 14:23:03 +08:00
2dust
baf90cfbdd Sing-box cache file specified path
https://github.com/2dust/v2rayN/issues/6460
2025-01-10 10:00:00 +08:00
2dust
1a5eeb9401 Adjust UI for desktop 2025-01-09 21:03:17 +08:00
2dust
e0ae101ff4 Adjust UI for desktop 2025-01-09 15:14:03 +08:00
Long Yixing
8b4a07dfe8 Modify the macos build script (#6461)
No longer generate AppIcon.icns
2025-01-09 10:21:07 +08:00
2dust
db934e70cb The icon of the system proxy can be customized
https://github.com/2dust/v2rayN/issues/6459
2025-01-08 20:35:33 +08:00
2dust
b770048f05 The exported routing rules are compatible with the import function of v2rayNG 2025-01-08 17:57:23 +08:00
2dust
27c53be209 up 7.5.6 2025-01-08 14:16:30 +08:00
2dust
d93c12b354 Add more options to xray fragment 2025-01-08 13:52:21 +08:00
2dust
98d4a47efb Fix Mux for XUDP
https://github.com/2dust/v2rayN/issues/6446
2025-01-07 20:16:05 +08:00
2dust
8ab04c65b5 Update README.md 2025-01-07 14:33:15 +08:00
2dust
1b2dab1388 Bug fix
https://github.com/2dust/v2rayN/issues/6448
2025-01-07 11:28:46 +08:00
2dust
4f8dae7fa0 Add the mixed option in Stack in Tun mode settings
https://github.com/2dust/v2rayN/issues/6441
2025-01-06 20:46:07 +08:00
Harry Huang
cdc23e32c4 Fix zh-Hans and zh-Hant translation style (#6443)
* Fix zh-Hans i10n translation style

* Fix zh-Hant i10n translation style
2025-01-06 19:05:43 +08:00
2dust
20457e9e63 up 7.5.5 2025-01-05 19:10:57 +08:00
2dust
e63042af84 Bug fix for fontsize 2025-01-05 19:10:12 +08:00
2dust
c35b4d3c1b up 7.5.4 2025-01-05 17:58:55 +08:00
2dust
64a83a5d64 down PackageReference 2025-01-05 17:58:23 +08:00
2dust
01039d0b47 up 7.5.3 2025-01-05 17:31:32 +08:00
2dust
7c1e5a3cba Fixed possible crash issues 2025-01-05 17:12:51 +08:00
2dust
038161527f Buf fix for CurrentFontSize 2025-01-05 17:11:32 +08:00
2dust
b12b7a17e6 Fix possible issues with load balancing 2025-01-05 16:31:32 +08:00
2dust
37cf23d5fe up PackageReference 2025-01-05 15:01:15 +08:00
2dust
ed7fb4f6e3 Code clean 2025-01-05 14:50:31 +08:00
2dust
5d4bd2fee6 Fix possible issues with load balancing
https://github.com/2dust/v2rayN/issues/6429
2025-01-05 14:49:53 +08:00
2dust
aae5906311 Fix GetListNetworkServices 2025-01-05 12:24:14 +08:00
2dust
4a7bafd011 Fix Linux restore backup function
Fixed the issue that the guiNConfig.json file cannot be restored in the backup and restore function
2025-01-05 10:22:18 +08:00
2dust
626ebfe65d Improved ModifyFontSize 2025-01-04 20:42:42 +08:00
2dust
3cc75cd46d up 7.5.2 2025-01-04 19:07:16 +08:00
2dust
f809ee7b20 Adjust the macos package icon
https://github.com/2dust/v2rayN/issues/6404
2025-01-04 19:06:26 +08:00
2dust
1295d8191c Fix DNS
https://github.com/2dust/v2rayN/issues/6416
2025-01-04 17:47:54 +08:00
2dust
bc2adbfa77 Add restart to Linux restore backup function 2025-01-04 17:03:12 +08:00
2dust
9583dff176 Added the function of restarting the main app to AmazTool 2025-01-04 17:01:57 +08:00
2dust
5732b84a7b Refactor KillProcess 2025-01-04 15:06:30 +08:00
2dust
c0d27504ac Refactor ProcessStart RebootAsAdmin 2025-01-03 20:56:51 +08:00
2dust
3db1dd7bbb Add a title to SaveLog 2025-01-03 15:02:31 +08:00
2dust
5392766c5e Improved KillProcess 2025-01-03 15:01:30 +08:00
2dust
730b7dea37 Adjust upgrade waiting time 2025-01-03 09:50:21 +08:00
2dust
02a13ce028 Add logging to KillProcess
https://github.com/2dust/v2rayN/issues/6386
2025-01-02 13:54:17 +08:00
2dust
7884853098 Improved backup and restore
Overwrite the configuration file directly in the main program
2025-01-02 13:36:26 +08:00
2dust
e122ea8146 Optimize VerticalAlignment="Center" 2025-01-02 12:20:43 +08:00
2dust
f500d2b9f4 up 7.5.1 2025-01-01 16:25:53 +08:00
2dust
79e53bf1f5 Improve macos system proxy code 2025-01-01 14:24:23 +08:00
2dust
31de7ec094 Bug fix SetLinuxChmod 2025-01-01 12:27:49 +08:00
2dust
2e4501187c Window title display adjustment
https://github.com/2dust/v2rayN/issues/6389
2025-01-01 10:38:55 +08:00
2dust
4430c9bd74 Remove the last rule from the Whitelist
https://github.com/2dust/v2rayN/issues/6378
2024-12-31 20:37:14 +08:00
2dust
cf8be85ff7 Remove the display of run as an administrator in Linux and macos 2024-12-31 16:30:27 +08:00
2dust
0759be1223 Fix rule required
https://github.com/2dust/v2rayN/issues/6378
2024-12-31 15:32:31 +08:00
2dust
21f8ddcf9f macos adds system proxy for USB
https://github.com/2dust/v2rayN/issues/6381
2024-12-31 14:55:35 +08:00
2dust
37cba5ee34 Fix export rule order issue
https://github.com/2dust/v2rayN/issues/6377
2024-12-31 14:15:09 +08:00
OnceUponATimeInAmerica
ff642fd1ac Add full support for (one-click) Iran regional preset by using Chocolate4U's github repos for iran routing rules (#6384) 2024-12-31 13:51:06 +08:00
2dust
647f1d9c8b up 7.5.0 2024-12-30 19:56:33 +08:00
2dust
d886195ee3 Adjust upgrade waiting time 2024-12-30 19:55:32 +08:00
2dust
e2b8f4f89a If Process.start contains spaces, add quotes 2024-12-30 19:33:39 +08:00
2dust
1dcfe661e9 Modify the build script
When NotStoreConfigHere.txt file exists, the configs not stored in the current folder
2024-12-30 18:16:07 +08:00
2dust
d6dd110781 Adjust open the storage location 2024-12-30 11:10:27 +08:00
2dust
a0f956c885 Add command shortcut keys for macos
https://github.com/2dust/v2rayN/issues/6375
2024-12-30 11:02:09 +08:00
Long Yixing
88bcafed97 Modify the build macos script (#6374) 2024-12-30 09:24:22 +08:00
2dust
6e4f15ab52 Update README.md 2024-12-27 10:12:38 +08:00
Wydy
20cae1ff4d Update pac (#6356) 2024-12-27 09:48:28 +08:00
2dust
dcf621b822 Modify the build script 2024-12-26 17:19:42 +08:00
2dust
eafa20032b Modify the build windows script 2024-12-25 17:06:03 +08:00
2dust
7375e1a490 Modify the build macos script 2024-12-25 16:48:23 +08:00
2dust
199d87ba84 Modify the build linux script and add release package deb 2024-12-25 16:11:02 +08:00
2dust
b43975ebfc Add v2rayN.png for desktop 2024-12-25 16:06:11 +08:00
2dust
fe7314c978 up 7.4.2 2024-12-24 10:55:25 +08:00
2dust
d4eb8e59a6 update build 2024-12-23 17:39:50 +08:00
2dust
8ee00907b7 update build 2024-12-23 17:34:06 +08:00
2dust
25fddc3c71 Code clean for desktop 2024-12-23 14:28:33 +08:00
2dust
c78b733850 Revert "update build macos"
This reverts commit a57c83125e.
2024-12-23 13:59:55 +08:00
2dust
a57c83125e update build macos 2024-12-23 12:12:03 +08:00
2dust
247b59985f update build 2024-12-23 11:31:56 +08:00
2dust
7470b8b6d3 Try to fix
https://github.com/2dust/v2rayN/issues/6073
2024-12-23 10:38:37 +08:00
2dust
776d37b7aa Optimize port display 2024-12-23 10:37:43 +08:00
alphax-hue3682
8f532f8468 Update persian translate (#6325) 2024-12-23 10:00:51 +08:00
2dust
472963fe2d Add a second local listening port
https://github.com/2dust/v2rayN/issues/6321
2024-12-22 20:03:20 +08:00
2dust
6a9b62ab9a Improve Ctrl+V for Windows 2024-12-22 12:02:00 +08:00
2dust
9ac8aa2969 up PackageReference 2024-12-22 12:00:50 +08:00
2dust
838bd2c794 up 7.4.1 2024-12-19 16:18:45 +08:00
2dust
b2bbe432e0 Fix
https://github.com/2dust/v2rayN/issues/6309
2024-12-19 16:07:45 +08:00
2dust
b3d8042452 The lower limit of the font size from 10 to 8 2024-12-19 13:53:40 +08:00
2dust
0c758a7fdc Optimize UI for macos 2024-12-19 13:36:45 +08:00
2dust
85cb1d1c92 Bug fix system proxy for macos 2024-12-19 13:20:12 +08:00
2dust
2cd2e8894d Add system proxy exception function for macos 2024-12-19 11:40:16 +08:00
2dust
abb58379b3 Add IsNonWindows instead of IsLinux or IsOSX 2024-12-19 11:24:52 +08:00
2dust
4f48e8b190 Optimize UI 2024-12-19 10:23:46 +08:00
2dust
2b5cbb5e74 UnauthorizedAccessException to Exception 2024-12-18 15:27:00 +08:00
2dust
23dd140921 up 7.4.0 2024-12-18 14:47:27 +08:00
2dust
8c8d7bda64 StartupPath optional LocalApplicationData for linux 2024-12-18 10:27:58 +08:00
2dust
a6e246948a Linux system proxy adds kde version processing 2024-12-17 11:05:12 +08:00
2dust
c49ba735a0 Optimize code 2024-12-16 21:05:36 +08:00
2dust
1a33c598e8 Disable mux when using xhttp 2024-12-16 21:01:03 +08:00
2dust
a4bbdb49de proxy api.ip.sb
https://github.com/2dust/v2rayN/issues/6280
2024-12-16 19:59:46 +08:00
2dust
cf3846fbfd Update README.md 2024-12-16 19:47:27 +08:00
2dust
d46943eedf Optimize UI 2024-12-16 14:28:22 +08:00
2dust
3bc17bd50a Add host for xray ws
https://github.com/XTLS/Xray-core/pull/4142
2024-12-16 14:22:31 +08:00
2dust
48a159f4c8 Need SkiaSharp V2.88 2024-12-15 16:15:58 +08:00
2dust
3d1bcffdc5 up 7.3.2 2024-12-15 15:14:25 +08:00
2dust
45fa0f94d2 up PackageReference 2024-12-15 15:13:37 +08:00
2dust
ed16b7de4a Fix
https://github.com/2dust/v2rayN/issues/6258
2024-12-15 14:41:48 +08:00
2dust
f2ec03c7ec Bug fix
https://github.com/2dust/v2rayN/issues/6263
2024-12-15 14:41:29 +08:00
2dust
11db87f1e6 Remove unused resources 2024-12-15 14:27:00 +08:00
phoenix6936
a1feaf33e0 Update persian translation (#6245)
* Update persian translation

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

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

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

* Update ResUI.fa-Ir.resx

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

Publish to winget after release

* Update winget-publish.yml

change to released trigger

* Create winget-pre-release-publish.yml

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

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

* Update AesUtils.cs

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

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

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

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

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

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

* fix

* 移除自述

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

* 小修正

* 修正

* 更正自述

* 应该完成了

* 内嵌资源

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

* fix

* 移除自述

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

* 小修正

* 修正

* 更正自述

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

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

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

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

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

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

* 修复:点击表头排序时,超时服务器排在前面的问题
2024-11-08 09:21:43 +08:00
DecorativeFamily
c4b490e46d [CodeFactor] Apply fixes (#6005)
Co-authored-by: codefactor-io <support@codefactor.io>
2024-11-07 14:46:27 +08:00
253 changed files with 19875 additions and 33273 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]: "
labels: ["bug"]
body:
- type: input
id: "os-version"
attributes:
label: "操作系统和版本"
description: "操作系统和版本"
validations:
required: true
- type: input
id: "expectation"
attributes:

View File

@@ -1,10 +1,11 @@
# Set update schedule for GitHub Actions
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every daily
interval: "daily"
- package-ecosystem: "nuget"
directory: "/"
schedule:
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 }}\"
}
}"

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

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

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

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

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

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

@@ -0,0 +1,71 @@
name: release Windows
on:
workflow_dispatch:
inputs:
release_tag:
required: false
type: string
push:
branches:
- master
env:
OutputArch: "windows-64"
OutputArchArm: "windows-arm64"
OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64"
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64"
OutputPath64Sc: "${{ github.workspace }}/v2rayN/Release/windows-64-SelfContained"
jobs:
build:
strategy:
matrix:
configuration: [Release]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
- name: Setup
uses: actions/setup-dotnet@v4.3.0
with:
dotnet-version: '8.0.x'
- name: Build
run: |
cd v2rayN
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:EnableWindowsTargeting=true -o $OutputPathArm64
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:EnableWindowsTargeting=true -o $OutputPath64
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:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc
- name: Upload build artifacts
uses: actions/upload-artifact@v4.6.1
with:
name: v2rayN-windows
path: |
${{ github.workspace }}/v2rayN/Release/windows*
# release zip archive
- name: Package release zip archive
if: github.event.inputs.release_tag != ''
run: |
chmod 755 package-release-zip.sh
./package-release-zip.sh $OutputArch $OutputPath64
./package-release-zip.sh $OutputArchArm $OutputPathArm64
./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc
- name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/v2rayN*.zip
tag: ${{ github.event.inputs.release_tag }}
file_glob: true
prerelease: true

View File

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

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

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

415
.gitignore vendored
View File

@@ -1,19 +1,400 @@
################################################################################
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
################################################################################
## 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/main/VisualStudio.gitignore
/v2rayN/.vs/
/v2rayN/v2rayN/bin/Debug/app.publish
/v2rayN/v2rayN/bin/Debug
/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-specific files
*.rsuser
*.suo
*.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
A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
A GUI client for Windows, Linux and macOS, support [Xray](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)
@@ -9,15 +9,8 @@ A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core)
## How to use
- If you are new to this, please download v2rayN-With-Core.zip from [releases](https://github.com/2dust/v2rayN/releases)
- Otherwise please download v2rayN.zip (you will also need to download cores in the bin directory)
- Run v2rayN.exe
## Requirements
- (6.35 and above)[Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- (6.33 and below)[Microsoft .NET 6.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [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
[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

58
package-debian.sh Normal file
View File

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

58
package-osx.sh Executable file
View File

@@ -0,0 +1,58 @@
#!/bin/bash
Arch="$1"
OutputPath="$2"
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}"
mkdir -p "$PackagePath/v2rayN.app/Contents/Resources"
cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS"
cp -f "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.icns" "$PackagePath/v2rayN.app/Contents/Resources/AppIcon.icns"
echo "When this file exists, app will not store configs under this folder" > "$PackagePath/v2rayN.app/Contents/MacOS/NotStoreConfigHere.txt"
chmod +x "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN"
cat >"$PackagePath/v2rayN.app/Contents/Info.plist" <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDisplayName</key>
<string>v2rayN</string>
<key>CFBundleExecutable</key>
<string>v2rayN</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>2dust.v2rayN</string>
<key>CFBundleName</key>
<string>v2rayN</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${Version}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
EOF
create-dmg \
--volname "v2rayN Installer" \
--window-size 700 420 \
--icon-size 100 \
--icon "v2rayN.app" 160 185 \
--hide-extension "v2rayN.app" \
--app-drop-link 500 185 \
"v2rayN-${Arch}.dmg" \
"$PackagePath/v2rayN.app"

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

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

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

@@ -1,12 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
<FileVersion>1.3.0</FileVersion>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Update="Resx\Resource.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
</EmbeddedResource>
<Compile Update="Resx\Resource.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resource.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@@ -1,22 +1,26 @@
namespace AmazTool
namespace AmazTool
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
private static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Please run it from the main application.(请从主应用运行)");
Console.WriteLine(Resx.Resource.Guidelines);
Thread.Sleep(5000);
return;
}
var fileName = Uri.UnescapeDataString(string.Join(" ", args));
UpgradeApp.Upgrade(fileName);
var argData = Uri.UnescapeDataString(string.Join(" ", args));
if (argData.Equals("rebootas"))
{
Thread.Sleep(1000);
Utils.StartV2RayN();
return;
}
UpgradeApp.Upgrade(argData);
}
}
}
}

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

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.IO.Compression;
using System.Text;
@@ -8,44 +8,46 @@ namespace AmazTool
{
public static void Upgrade(string fileName)
{
Console.WriteLine(fileName);
Console.WriteLine("In progress, please wait...(正在进行中,请等待)");
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
Thread.Sleep(9000);
Utils.Waiting(5);
if (!File.Exists(fileName))
{
Console.WriteLine("Upgrade Failed, File Not Exist(升级失败,文件不存在).");
Console.WriteLine(Resx.Resource.UpgradeFileNotFound);
return;
}
Console.WriteLine("Try to end the process(尝试结束进程).");
Console.WriteLine(Resx.Resource.TryTerminateProcess);
try
{
var existing = Process.GetProcessesByName(V2rayN);
var existing = Process.GetProcessesByName(Utils.V2rayN);
foreach (var pp in existing)
{
pp?.Kill();
pp?.WaitForExit(1000);
var path = pp.MainModule?.FileName ?? "";
if (path.StartsWith(Utils.GetPath(Utils.V2rayN)))
{
pp?.Kill();
pp?.WaitForExit(1000);
}
}
}
catch (Exception ex)
{
// Access may be denied without admin right. The user may not be an administrator.
Console.WriteLine("Failed to close v2rayN(关闭v2rayN失败).\n" +
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace);
Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
}
Console.WriteLine("Start extracting files(开始解压文件).");
Console.WriteLine(Resx.Resource.StartUnzipping);
StringBuilder sb = new();
try
{
string thisAppOldFile = $"{GetExePath()}.tmp";
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
File.Delete(thisAppOldFile);
string splitKey = "/";
var splitKey = "/";
using ZipArchive archive = ZipFile.OpenRead(fileName);
foreach (ZipArchiveEntry entry in archive.Entries)
using var archive = ZipFile.OpenRead(fileName);
foreach (var entry in archive.Entries)
{
try
{
@@ -57,17 +59,35 @@ namespace AmazTool
Console.WriteLine(entry.FullName);
var lst = entry.FullName.Split(splitKey);
if (lst.Length == 1) continue;
string fullName = string.Join(splitKey, lst[1..lst.Length]);
if (string.Equals(GetExePath(), GetPath(fullName), StringComparison.OrdinalIgnoreCase))
if (lst.Length == 1)
{
File.Move(GetExePath(), thisAppOldFile);
continue;
}
string entryOutputPath = GetPath(fullName);
var fullName = string.Join(splitKey, lst[1..lst.Length]);
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
{
File.Move(Utils.GetExePath(), thisAppOldFile);
}
var entryOutputPath = Utils.GetPath(fullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
entry.ExtractToFile(entryOutputPath, true);
//In the bin folder, if the file already exists, it will be skipped
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
{
continue;
}
try
{
entry.ExtractToFile(entryOutputPath, true);
}
catch
{
Thread.Sleep(1000);
entry.ExtractToFile(entryOutputPath, true);
}
Console.WriteLine(entryOutputPath);
}
@@ -79,49 +99,19 @@ namespace AmazTool
}
catch (Exception ex)
{
Console.WriteLine("Upgrade Failed(升级失败)." + ex.StackTrace);
Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
//return;
}
if (sb.Length > 0)
{
Console.WriteLine("Upgrade Failed(升级失败)." + sb.ToString());
Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
//return;
}
Console.WriteLine("Start v2rayN, please wait...(正在重启,请等待)");
Thread.Sleep(9000);
Process process = new()
{
StartInfo = new()
{
UseShellExecute = true,
FileName = V2rayN,
WorkingDirectory = StartupPath()
}
};
process.Start();
}
Console.WriteLine(Resx.Resource.Restartv2rayN);
Utils.Waiting(2);
private static string GetExePath()
{
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
Utils.StartV2RayN();
}
private static string StartupPath()
{
return AppDomain.CurrentDomain.BaseDirectory;
}
private static string GetPath(string fileName)
{
string startupPath = StartupPath();
if (string.IsNullOrEmpty(fileName))
{
return startupPath;
}
return Path.Combine(startupPath, fileName);
}
private static string V2rayN => "v2rayN";
}
}
}

52
v2rayN/AmazTool/Utils.cs Normal file
View File

@@ -0,0 +1,52 @@
using System.Diagnostics;
namespace AmazTool
{
internal class Utils
{
public static string GetExePath()
{
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
}
public static string StartupPath()
{
return AppDomain.CurrentDomain.BaseDirectory;
}
public static string GetPath(string fileName)
{
var startupPath = StartupPath();
if (string.IsNullOrEmpty(fileName))
{
return startupPath;
}
return Path.Combine(startupPath, fileName);
}
public static string V2rayN => "v2rayN";
public static void StartV2RayN()
{
Process process = new()
{
StartInfo = new()
{
UseShellExecute = true,
FileName = V2rayN,
WorkingDirectory = StartupPath()
}
};
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.5</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.5" />
<PackageVersion Include="Avalonia.Desktop" Version="11.2.5" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.5" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.5" />
<PackageVersion Include="CliWrap" Version="3.8.2" />
<PackageVersion Include="Downloader" Version="3.3.4" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.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.5" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.5" />
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
<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 ef73fa22c4

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
using Downloader;
using System.Net;
using Downloader;
namespace ServiceLib.Common
{
@@ -10,7 +10,7 @@ namespace ServiceLib.Common
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
{
if (Utils.IsNullOrEmpty(url))
if (url.IsNullOrEmpty())
{
return null;
}
@@ -18,7 +18,7 @@ namespace ServiceLib.Common
Uri uri = new(url);
//Authorization Header
var headers = new WebHeaderCollection();
if (Utils.IsNotEmpty(uri.UserInfo))
if (uri.UserInfo.IsNotEmpty())
{
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
}
@@ -56,7 +56,7 @@ namespace ServiceLib.Common
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
{
if (Utils.IsNullOrEmpty(url))
if (url.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(url));
}
@@ -86,7 +86,7 @@ namespace ServiceLib.Common
//};
downloader.DownloadProgressChanged += (sender, value) =>
{
var ts = (DateTime.Now - totalDatetime);
var ts = DateTime.Now - totalDatetime;
if (progress != null && ts.Seconds > totalSecond)
{
hasValue = true;
@@ -119,11 +119,11 @@ namespace ServiceLib.Common
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
{
if (Utils.IsNullOrEmpty(url))
if (url.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(url));
}
if (Utils.IsNullOrEmpty(fileName))
if (fileName.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(fileName));
}
@@ -146,10 +146,7 @@ namespace ServiceLib.Common
var progressPercentage = 0;
var hasValue = false;
await using var downloader = new Downloader.DownloadService(downloadOpt);
downloader.DownloadStarted += (sender, value) =>
{
progress?.Report(0);
};
downloader.DownloadStarted += (sender, value) => progress?.Report(0);
downloader.DownloadProgressChanged += (sender, value) =>
{
hasValue = true;
@@ -181,4 +178,4 @@ namespace ServiceLib.Common
downloadOpt = null;
}
}
}
}

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

@@ -1,4 +1,4 @@
using System.Formats.Tar;
using System.Formats.Tar;
using System.IO.Compression;
using System.Text;
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
{
public static class FileManager
{
private static readonly string _tag = "FileManager";
public static bool ByteArrayToFile(string fileName, byte[] content)
{
try
@@ -15,7 +17,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return false;
}
@@ -30,7 +32,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
@@ -46,7 +48,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
@@ -60,7 +62,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
@@ -79,7 +81,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
throw;
}
}
@@ -97,7 +99,7 @@ namespace ServiceLib.Common
}
try
{
if (Utils.IsNotEmpty(ignoredName) && entry.Name.Contains(ignoredName))
if (ignoredName.IsNotEmpty() && entry.Name.Contains(ignoredName))
{
continue;
}
@@ -105,13 +107,13 @@ namespace ServiceLib.Common
}
catch (IOException ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return false;
}
return true;
@@ -130,7 +132,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return null;
}
}
@@ -148,31 +150,33 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return false;
}
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
var dir = new DirectoryInfo(sourceDir);
// Check if the source directory exists
if (!dir.Exists)
{
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
}
// Cache directories before we start copying
var dirs = dir.GetDirectories();
// Create the destination directory
Directory.CreateDirectory(destinationDir);
_ = Directory.CreateDirectory(destinationDir);
// Get the files in the source directory and copy to the destination directory
foreach (var file in dir.GetFiles())
{
if (Utils.IsNotEmpty(ignoredName) && file.Name.Contains(ignoredName))
if (ignoredName.IsNotEmpty() && file.Name.Contains(ignoredName))
{
continue;
}
@@ -181,7 +185,11 @@ namespace ServiceLib.Common
continue;
}
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
@@ -190,9 +198,30 @@ namespace ServiceLib.Common
foreach (var subDir in dirs)
{
var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
CopyDirectory(subDir.FullName, newDestinationDir, true, ignoredName);
CopyDirectory(subDir.FullName, newDestinationDir, true, overwrite, ignoredName);
}
}
}
public static void DeleteExpiredFiles(string sourceDir, DateTime dtLine)
{
try
{
var files = Directory.GetFiles(sourceDir, "*.*");
foreach (var filePath in files)
{
var file = new FileInfo(filePath);
if (file.CreationTime >= dtLine)
{
continue;
}
file.Delete();
}
}
catch
{
// ignored
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Net.Http.Headers;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
@@ -10,7 +10,7 @@ namespace ServiceLib.Common
{
private static readonly Lazy<HttpClientHelper> _instance = new(() =>
{
HttpClientHandler handler = new() { UseCookies = false };
SocketsHttpHandler handler = new() { UseCookies = false };
HttpClientHelper helper = new(new HttpClient(handler));
return helper;
});
@@ -18,12 +18,17 @@ namespace ServiceLib.Common
public static HttpClientHelper Instance => _instance.Value;
private readonly HttpClient httpClient;
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
private HttpClientHelper(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public async Task<string?> TryGetAsync(string url)
{
if (Utils.IsNullOrEmpty(url))
if (url.IsNullOrEmpty())
{
return null;
}
try
{
@@ -38,13 +43,19 @@ namespace ServiceLib.Common
public async Task<string?> GetAsync(string url)
{
if (Utils.IsNullOrEmpty(url)) return null;
if (url.IsNullOrEmpty())
{
return null;
}
return await httpClient.GetStringAsync(url);
}
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
{
if (Utils.IsNullOrEmpty(url)) return null;
if (url.IsNullOrEmpty())
{
return null;
}
return await client.GetStringAsync(url, token);
}
@@ -53,13 +64,13 @@ namespace ServiceLib.Common
var jsonContent = JsonUtils.Serialize(headers);
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
var result = await httpClient.PutAsync(url, content);
await httpClient.PutAsync(url, content);
}
public async Task PatchAsync(string url, Dictionary<string, string> headers)
{
var myContent = JsonUtils.Serialize(headers);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var buffer = Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
@@ -75,11 +86,17 @@ namespace ServiceLib.Common
{
ArgumentNullException.ThrowIfNull(url);
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);
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 canReportProgress = total != -1 && progress != null;
@@ -97,8 +114,11 @@ namespace ServiceLib.Common
var read = await stream.ReadAsync(buffer, token);
totalRead += read;
if (read == 0) break;
await file.WriteAsync(buffer, 0, read, token);
if (read == 0)
{
break;
}
await file.WriteAsync(buffer.AsMemory(0, read), token);
if (canReportProgress)
{
@@ -118,7 +138,7 @@ namespace ServiceLib.Common
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
{
if (Utils.IsNullOrEmpty(url))
if (url.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(url));
}
@@ -168,7 +188,7 @@ namespace ServiceLib.Common
totalRead += read;
var ts = (DateTime.Now - totalDatetime);
var ts = DateTime.Now - totalDatetime;
if (progress != null && ts.Seconds > totalSecond)
{
totalSecond = ts.Seconds;
@@ -183,4 +203,4 @@ namespace ServiceLib.Common
} while (isMoreToRead);
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ServiceLib.Common
@@ -15,27 +15,29 @@ namespace ServiceLib.Common
public Job()
{
handle = CreateJobObject(IntPtr.Zero, null);
IntPtr extendedInfoPtr = IntPtr.Zero;
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
var extendedInfoPtr = IntPtr.Zero;
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
LimitFlags = 0x2000
};
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
BasicLimitInformation = info
};
try
{
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
extendedInfoPtr = Marshal.AllocHGlobal(length);
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr,
(uint)length))
{
throw new Exception(string.Format("Unable to set information. Error: {0}",
Marshal.GetLastWin32Error()));
}
}
finally
{
@@ -48,7 +50,7 @@ namespace ServiceLib.Common
public bool AddProcess(IntPtr processHandle)
{
bool succ = AssignProcessToJobObject(handle, processHandle);
var succ = AssignProcessToJobObject(handle, processHandle);
if (!succ)
{
@@ -75,7 +77,10 @@ namespace ServiceLib.Common
private void Dispose(bool disposing)
{
if (disposed) return;
if (disposed)
{
return;
}
disposed = true;
if (disposing)
@@ -103,7 +108,7 @@ namespace ServiceLib.Common
private static extern IntPtr CreateJobObject(IntPtr a, string? lpName);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
@@ -120,34 +125,34 @@ namespace ServiceLib.Common
[StructLayout(LayoutKind.Sequential)]
internal struct IO_COUNTERS
{
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
public ulong ReadOperationCount;
public ulong WriteOperationCount;
public ulong OtherOperationCount;
public ulong ReadTransferCount;
public ulong WriteTransferCount;
public ulong OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public UInt32 LimitFlags;
public long PerProcessUserTimeLimit;
public long PerJobUserTimeLimit;
public uint LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public uint ActiveProcessLimit;
public UIntPtr Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
public uint PriorityClass;
public uint SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public uint nLength;
public IntPtr lpSecurityDescriptor;
public Int32 bInheritHandle;
public int bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
@@ -173,4 +178,4 @@ namespace ServiceLib.Common
}
#endregion Helper classes
}
}

View File

@@ -6,6 +6,8 @@ namespace ServiceLib.Common
{
public class JsonUtils
{
private static readonly string _tag = "JsonUtils";
/// <summary>
/// DeepCopy
/// </summary>
@@ -70,8 +72,9 @@ namespace ServiceLib.Common
/// </summary>
/// <param name="obj"></param>
/// <param name="indented"></param>
/// <param name="nullValue"></param>
/// <returns></returns>
public static string Serialize(object? obj, bool indented = true)
public static string Serialize(object? obj, bool indented = true, bool nullValue = false)
{
var result = string.Empty;
try
@@ -82,14 +85,38 @@ namespace ServiceLib.Common
}
var options = new JsonSerializerOptions
{
WriteIndented = indented ? true : false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
WriteIndented = indented,
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
};
result = JsonSerializer.Serialize(obj, options);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return result;
}
/// <summary>
/// Serialize Object to Json string
/// </summary>
/// <param name="obj"></param>
/// <param name="options"></param>
/// <returns></returns>
public static string Serialize(object? obj, JsonSerializerOptions options)
{
var result = string.Empty;
try
{
if (obj == null)
{
return result;
}
result = JsonSerializer.Serialize(obj, options);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return result;
}
@@ -100,38 +127,5 @@ namespace ServiceLib.Common
/// <param name="obj"></param>
/// <returns></returns>
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
/// <summary>
/// Save as json file
/// </summary>
/// <param name="obj"></param>
/// <param name="filePath"></param>
/// <param name="nullValue"></param>
/// <returns></returns>
public static int ToFile(object? obj, string? filePath, bool nullValue = true)
{
if (filePath is null)
{
return -1;
}
try
{
using var file = File.Create(filePath);
var options = new JsonSerializerOptions
{
WriteIndented = true,
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
};
JsonSerializer.Serialize(file, obj, options);
return 0;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return -1;
}
}
}
}

View File

@@ -1,4 +1,4 @@
using NLog;
using NLog;
using NLog.Config;
using NLog.Targets;
@@ -25,46 +25,22 @@ namespace ServiceLib.Common
}
}
public static void ClearLogs()
{
Task.Run(() =>
{
try
{
var now = DateTime.Now.AddMonths(-1);
var dir = Utils.GetLogPath();
var files = Directory.GetFiles(dir, "*.txt");
foreach (var filePath in files)
{
var file = new FileInfo(filePath);
if (file.CreationTime >= now) continue;
try
{
file.Delete();
}
catch
{
// ignored
}
}
}
catch
{
// ignored
}
});
}
public static void SaveLog(string strContent)
{
if (!LogManager.IsLoggingEnabled()) return;
if (!LogManager.IsLoggingEnabled())
{
return;
}
LogManager.GetLogger("Log1").Info(strContent);
}
public static void SaveLog(string strTitle, Exception ex)
{
if (!LogManager.IsLoggingEnabled()) return;
if (!LogManager.IsLoggingEnabled())
{
return;
}
var logger = LogManager.GetLogger("Log2");
logger.Debug($"{strTitle},{ex.Message}");
@@ -75,4 +51,4 @@ namespace ServiceLib.Common
}
}
}
}
}

View File

@@ -0,0 +1,182 @@
using System.Diagnostics;
namespace ServiceLib.Common;
public static class ProcUtils
{
private static readonly string _tag = "ProcUtils";
public static void ProcessStart(string? fileName, string arguments = "")
{
_ = ProcessStart(fileName, arguments, null);
}
public static int? ProcessStart(string? fileName, string arguments, string? dir)
{
if (fileName.IsNullOrEmpty())
{
return null;
}
try
{
if (fileName.Contains(' '))
{
fileName = fileName.AppendQuotes();
}
if (arguments.Contains(' '))
{
arguments = arguments.AppendQuotes();
}
Process proc = new()
{
StartInfo = new ProcessStartInfo
{
UseShellExecute = true,
FileName = fileName,
Arguments = arguments,
WorkingDirectory = dir ?? string.Empty
}
};
_ = proc.Start();
return dir is null ? null : proc.Id;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return null;
}
public static void RebootAsAdmin(bool blAdmin = true)
{
try
{
ProcessStartInfo startInfo = new()
{
UseShellExecute = true,
Arguments = Global.RebootAs,
WorkingDirectory = Utils.StartupPath(),
FileName = Utils.GetExePath().AppendQuotes(),
Verb = blAdmin ? "runas" : null,
};
_ = Process.Start(startInfo);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public static async Task ProcessKill(int pid)
{
try
{
await ProcessKill(Process.GetProcessById(pid), false);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
public static async Task ProcessKill(Process? proc, bool review)
{
if (proc is null)
{
return;
}
GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName);
try
{
if (Utils.IsNonWindows())
{
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 ProcessKillByKeyInfo(review, procId, fileName, processName);
}
private static void GetProcessKeyInfo(Process? proc, bool review, out int? procId, out string? fileName, out string? processName)
{
procId = null;
fileName = null;
processName = null;
if (!review)
{
return;
}
try
{
procId = proc?.Id;
fileName = proc?.MainModule?.FileName;
processName = proc?.ProcessName;
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
private static async Task ProcessKillByKeyInfo(bool review, int? procId, string? fileName, string? processName)
{
if (review && procId != null && fileName != null)
{
try
{
var lstProc = Process.GetProcessesByName(processName);
foreach (var proc2 in lstProc)
{
if (proc2.Id == procId)
{
Logging.SaveLog($"{_tag}, KillProcess not completing the job, procId");
await ProcessKill(proc2, false);
}
if (proc2.MainModule != null && proc2.MainModule?.FileName == fileName)
{
Logging.SaveLog($"{_tag}, KillProcess not completing the job, fileName");
}
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
}
}
}

View File

@@ -60,7 +60,7 @@ namespace ServiceLib.Common
var reader = new BarcodeReader();
var result = reader.Decode(bitmap);
if (result != null && Utils.IsNotEmpty(result.Text))
if (result != null && result.Text.IsNotEmpty())
{
return result.Text;
}

View File

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

View File

@@ -1,29 +1,29 @@
namespace ServiceLib.Common
namespace ServiceLib.Common
{
public class SemanticVersion
{
private int major;
private int minor;
private int patch;
private string version;
private readonly int major;
private readonly int minor;
private readonly int patch;
private readonly string version;
public SemanticVersion(int major, int minor, int patch)
{
this.major = major;
this.minor = minor;
this.patch = patch;
this.version = $"{major}.{minor}.{patch}";
version = $"{major}.{minor}.{patch}";
}
public SemanticVersion(string? version)
{
try
{
if (version.IsNullOrEmpty())
if (string.IsNullOrEmpty(version))
{
this.major = 0;
this.minor = 0;
this.patch = 0;
major = 0;
minor = 0;
patch = 0;
return;
}
this.version = version.RemovePrefix('v');
@@ -31,15 +31,15 @@
var parts = this.version.Split('.');
if (parts.Length == 2)
{
this.major = int.Parse(parts[0]);
this.minor = int.Parse(parts[1]);
this.patch = 0;
major = int.Parse(parts.First());
minor = int.Parse(parts.Last());
patch = 0;
}
else if (parts.Length is 3 or 4)
{
this.major = int.Parse(parts[0]);
this.minor = int.Parse(parts[1]);
this.patch = int.Parse(parts[2]);
major = int.Parse(parts[0]);
minor = int.Parse(parts[1]);
patch = int.Parse(parts[2]);
}
else
{
@@ -48,9 +48,9 @@
}
catch
{
this.major = 0;
this.minor = 0;
this.patch = 0;
major = 0;
minor = 0;
patch = 0;
}
}
@@ -58,7 +58,7 @@
{
if (obj is SemanticVersion other)
{
return this.major == other.major && this.minor == other.minor && this.patch == other.patch;
return major == other.major && minor == other.minor && patch == other.patch;
}
else
{
@@ -68,7 +68,7 @@
public override int GetHashCode()
{
return this.major.GetHashCode() ^ this.minor.GetHashCode() ^ this.patch.GetHashCode();
return major.GetHashCode() ^ minor.GetHashCode() ^ patch.GetHashCode();
}
/// <summary>
@@ -77,18 +77,18 @@
/// <returns>major.minor.patch</returns>
public override string ToString()
{
return this.version;
return version;
}
public string ToVersionString(string? prefix = null)
{
if (prefix == null)
{
return this.version;
return version;
}
else
{
return $"{prefix}{this.version}";
return $"{prefix}{version}";
}
}
@@ -108,31 +108,31 @@
private bool GreaterEquals(SemanticVersion other)
{
if (this.major < other.major)
if (major < other.major)
{
return false;
}
else if (this.major > other.major)
else if (major > other.major)
{
return true;
}
else
{
if (this.minor < other.minor)
if (minor < other.minor)
{
return false;
}
else if (this.minor > other.minor)
else if (minor > other.minor)
{
return true;
}
else
{
if (this.patch < other.patch)
if (patch < other.patch)
{
return false;
}
else if (this.patch > other.patch)
else if (patch > other.patch)
{
return true;
}
@@ -146,31 +146,31 @@
private bool LessEquals(SemanticVersion other)
{
if (this.major < other.major)
if (major < other.major)
{
return true;
}
else if (this.major > other.major)
else if (major > other.major)
{
return false;
}
else
{
if (this.minor < other.minor)
if (minor < other.minor)
{
return true;
}
else if (this.minor > other.minor)
else if (minor > other.minor)
{
return false;
}
else
{
if (this.patch < other.patch)
if (patch < other.patch)
{
return true;
}
else if (this.patch > other.patch)
else if (patch > other.patch)
{
return false;
}
@@ -184,4 +184,4 @@
#endregion Private
}
}
}

View File

@@ -1,5 +1,5 @@
using SQLite;
using System.Collections;
using SQLite;
namespace ServiceLib.Common
{
@@ -7,7 +7,7 @@ namespace ServiceLib.Common
{
private static readonly Lazy<SQLiteHelper> _instance = new(() => new());
public static SQLiteHelper Instance => _instance.Value;
private string _connstr;
private readonly string _connstr;
private SQLiteConnection _db;
private SQLiteAsyncConnection _dbAsync;
private readonly string _configDB = "guiNDB.db";
@@ -73,5 +73,19 @@ namespace ServiceLib.Common
{
return _dbAsync.Table<T>();
}
public async Task DisposeDbConnectionAsync()
{
await Task.Factory.StartNew(() =>
{
_db?.Close();
_db?.Dispose();
_db = null;
_dbAsync?.GetConnection()?.Close();
_dbAsync?.GetConnection()?.Dispose();
_dbAsync = null;
});
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
namespace ServiceLib.Common
{
@@ -6,7 +6,7 @@ namespace ServiceLib.Common
{
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
{
return string.IsNullOrEmpty(value);
return string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value);
}
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
@@ -21,8 +21,11 @@ namespace ServiceLib.Common
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
{
if (s.IsNullOrEmpty()) return false;
return chars.Contains(s[0]);
if (s.IsNullOrEmpty())
{
return false;
}
return chars.Contains(s.First());
}
private static bool IsWhiteSpace(this string value)
@@ -34,7 +37,10 @@ namespace ServiceLib.Common
{
while (reader.ReadLine() is { } line)
{
if (line.IsWhiteSpace()) continue;
if (line.IsWhiteSpace())
{
continue;
}
yield return line;
}
}
@@ -61,12 +67,17 @@ namespace ServiceLib.Common
return string.Empty;
}
return char.ToUpper(value[0]) + value[1..];
return char.ToUpper(value.First()) + value[1..];
}
public static string AppendQuotes(this string value)
{
return string.IsNullOrEmpty(value) ? string.Empty : $"\"{value}\"";
}
public static int ToInt(this string? value, int defaultValue = 0)
{
return int.TryParse(value, out var result) ? result : defaultValue;
}
}
}
}

View File

@@ -1,5 +1,3 @@
using CliWrap;
using CliWrap.Buffered;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Net;
@@ -10,143 +8,81 @@ using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using CliWrap;
using CliWrap.Buffered;
namespace ServiceLib.Common
{
public class 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(ex.Message, 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(ex.Message, ex);
}
return null;
}
#endregion
private static readonly string _tag = "Utils";
#region
/// <summary>
/// 转逗号分隔的字符串
/// Convert to comma-separated string
/// </summary>
/// <param name="lst"></param>
/// <param name="wrap"></param>
/// <returns></returns>
public static string List2String(List<string>? lst, bool wrap = false)
{
if (lst == null || lst.Count == 0)
{
return string.Empty;
}
var separator = wrap ? "," + Environment.NewLine : ",";
try
{
if (lst == null)
{
return string.Empty;
}
if (wrap)
{
return string.Join("," + Environment.NewLine, lst);
}
else
{
return string.Join(",", lst);
}
return string.Join(separator, lst);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return string.Empty;
}
return string.Empty;
}
/// <summary>
/// 逗号分隔的字符串
/// Comma-separated string
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static List<string>? String2List(string? str)
{
if (string.IsNullOrWhiteSpace(str))
{
return null;
}
try
{
if (str == null)
{
return null;
}
str = str.Replace(Environment.NewLine, "");
str = str.Replace(Environment.NewLine, string.Empty);
return new List<string>(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return null;
}
return null;
}
/// <summary>
/// 逗号分隔的字符串,先排序后转List
/// Comma-separated string, sorted and then converted to List
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static List<string>? String2ListSorted(string str)
{
try
{
str = str.Replace(Environment.NewLine, "");
List<string> list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
list.Sort();
return list;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
return null;
var lst = String2List(str);
lst?.Sort();
return lst;
}
/// <summary>
/// Base64编码
/// Base64 Encode
/// </summary>
/// <param name="plainText"></param>
/// <returns></returns>
@@ -159,14 +95,14 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog("Base64Encode", ex);
Logging.SaveLog(_tag, ex);
}
return string.Empty;
}
/// <summary>
/// Base64解码
/// Base64 Decode
/// </summary>
/// <param name="plainText"></param>
/// <returns></returns>
@@ -174,7 +110,11 @@ namespace ServiceLib.Common
{
try
{
if (plainText.IsNullOrEmpty()) return "";
if (plainText.IsNullOrEmpty())
{
return "";
}
plainText = plainText.Trim()
.Replace(Environment.NewLine, "")
.Replace("\n", "")
@@ -185,7 +125,7 @@ namespace ServiceLib.Common
if (plainText.Length % 4 > 0)
{
plainText = plainText.PadRight(plainText.Length + 4 - plainText.Length % 4, '=');
plainText = plainText.PadRight(plainText.Length + 4 - (plainText.Length % 4), '=');
}
var data = Convert.FromBase64String(plainText);
@@ -193,24 +133,12 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog("Base64Decode", ex);
Logging.SaveLog(_tag, ex);
}
return string.Empty;
}
public static int ToInt(object? obj)
{
try
{
return Convert.ToInt32(obj ?? string.Empty);
}
catch
{
return 0;
}
}
public static bool ToBool(object obj)
{
try
@@ -235,55 +163,25 @@ namespace ServiceLib.Common
}
}
private static void ToHumanReadable(long amount, out double result, out string unit)
{
var factor = 1024u;
//long KBs = amount / factor;
var KBs = amount;
if (KBs > 0)
{
// multi KB
var MBs = KBs / factor;
if (MBs > 0)
{
// multi MB
var GBs = MBs / factor;
if (GBs > 0)
{
// multi GB
var TBs = GBs / factor;
if (TBs > 0)
{
result = TBs + ((GBs % factor) / (factor + 0.0));
unit = "TB";
return;
}
result = GBs + ((MBs % factor) / (factor + 0.0));
unit = "GB";
return;
}
result = MBs + ((KBs % factor) / (factor + 0.0));
unit = "MB";
return;
}
result = KBs + ((amount % factor) / (factor + 0.0));
unit = "KB";
return;
}
else
{
result = amount;
unit = "B";
}
}
public static string HumanFy(long amount)
{
ToHumanReadable(amount, out var result, out var unit);
return $"{result:f1} {unit}";
if (amount <= 0)
{
return $"{amount:f1} B";
}
string[] units = ["KB", "MB", "GB", "TB", "PB"];
var unitIndex = 0;
double size = amount;
// Loop and divide by 1024 until a suitable unit is found
while (size >= 1024 && unitIndex < units.Length - 1)
{
size /= 1024;
unitIndex++;
}
return $"{size:f1} {units[unitIndex]}";
}
public static string UrlEncode(string url)
@@ -299,7 +197,7 @@ namespace ServiceLib.Common
public static NameValueCollection ParseQueryString(string query)
{
var result = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
if (IsNullOrEmpty(query))
if (query.IsNullOrEmpty())
{
return result;
}
@@ -313,8 +211,8 @@ namespace ServiceLib.Common
continue;
}
var key = Uri.UnescapeDataString(keyValue[0]);
var val = Uri.UnescapeDataString(keyValue[1]);
var key = Uri.UnescapeDataString(keyValue.First());
var val = Uri.UnescapeDataString(keyValue.Last());
if (result[key] is null)
{
@@ -327,15 +225,54 @@ namespace ServiceLib.Common
public static string GetMd5(string str)
{
var byteOld = Encoding.UTF8.GetBytes(str);
var byteNew = MD5.HashData(byteOld);
StringBuilder sb = new(32);
foreach (var b in byteNew)
if (string.IsNullOrEmpty(str))
{
sb.Append(b.ToString("x2"));
return string.Empty;
}
return sb.ToString();
try
{
var byteOld = Encoding.UTF8.GetBytes(str);
var byteNew = MD5.HashData(byteOld);
StringBuilder sb = new(32);
foreach (var b in byteNew)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return string.Empty;
}
}
public static string GetFileHash(string filePath)
{
if (string.IsNullOrEmpty(filePath))
{
return string.Empty;
}
if (!File.Exists(filePath))
{
return string.Empty;
}
try
{
using var md5 = MD5.Create();
using var stream = File.OpenRead(filePath);
var hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return string.Empty;
}
}
/// <summary>
@@ -345,7 +282,7 @@ namespace ServiceLib.Common
/// <returns></returns>
public static string GetPunycode(string url)
{
if (Utils.IsNullOrEmpty(url))
if (url.IsNullOrEmpty())
{
return url;
}
@@ -370,14 +307,15 @@ namespace ServiceLib.Common
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]);
return Convert.TryFromBase64String(plainText, buffer, out var _);
}
public static string Convert2Comma(string text)
{
if (IsNullOrEmpty(text))
if (text.IsNullOrEmpty())
{
return text;
}
@@ -390,7 +328,7 @@ namespace ServiceLib.Common
#region
/// <summary>
/// 判断输入的是否是数字
/// Determine if the input is a number
/// </summary>
/// <param name="oText"></param>
/// <returns></returns>
@@ -399,28 +337,13 @@ namespace ServiceLib.Common
return oText.All(char.IsNumber);
}
public static bool IsNullOrEmpty(string? text)
{
if (string.IsNullOrWhiteSpace(text))
{
return true;
}
return text == "null";
}
public static bool IsNotEmpty(string? text)
{
return !string.IsNullOrEmpty(text);
}
/// <summary>
/// 验证Domain地址是否合法
/// Validate if the domain address is valid
/// </summary>
/// <param name="domain"></param>
public static bool IsDomain(string? domain)
{
if (IsNullOrEmpty(domain))
if (domain.IsNullOrEmpty())
{
return false;
}
@@ -460,9 +383,12 @@ namespace ServiceLib.Common
if (IPAddress.TryParse(ip, out var address))
{
var ipBytes = address.GetAddressBytes();
if (ipBytes[0] == 10) return true;
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true;
if (ipBytes[0] == 192 && ipBytes[1] == 168) return true;
if (ipBytes[0] == 10)
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;
@@ -476,14 +402,26 @@ namespace ServiceLib.Common
{
try
{
var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
var ipEndPoints = ipProperties.GetActiveTcpListeners();
//var lstIpEndPoints = new List<IPEndPoint>(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
return ipEndPoints.Any(endPoint => endPoint.Port == port);
List<IPEndPoint> lstIpEndPoints = new();
List<TcpConnectionInformation> lstTcpConns = new();
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)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return false;
@@ -515,33 +453,27 @@ namespace ServiceLib.Common
#region
public static bool UpgradeAppExists(out string fileName)
public static bool UpgradeAppExists(out string upgradeFileName)
{
fileName = Path.Combine(Utils.StartupPath(), GetExeName("AmazTool"));
return File.Exists(fileName);
upgradeFileName = Path.Combine(GetBaseDirectory(), GetExeName("AmazTool"));
return File.Exists(upgradeFileName);
}
/// <summary>
/// 取得版本
/// Get version
/// </summary>
/// <returns></returns>
public static string GetVersion(bool blFull = true)
{
try
{
if (blFull)
{
return
$"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture} - {File.GetLastWriteTime(GetExePath()):yyyy/MM/dd}";
}
else
{
return $"{Global.AppName}/{GetVersionInfo()}";
}
return blFull
? $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture}"
: $"{Global.AppName}/{GetVersionInfo()}";
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return Global.AppName;
@@ -555,13 +487,18 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return "0.0";
}
}
public static string GetRuntimeInfo()
{
return $"{Utils.GetVersion()} | {Utils.StartupPath()} | {Utils.GetExePath()} | {Environment.OSVersion}";
}
/// <summary>
/// 取得GUID
/// GUID
/// </summary>
/// <returns></returns>
public static string GetGuid(bool full = true)
@@ -579,7 +516,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return string.Empty;
@@ -590,23 +527,6 @@ namespace ServiceLib.Common
return Guid.TryParse(strSrc, out _);
}
public static void ProcessStart(string? fileName, string arguments = "")
{
try
{
if (fileName.IsNullOrEmpty())
{
return;
}
Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true });
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
public static Dictionary<string, string> GetSystemHosts()
{
var systemHosts = new Dictionary<string, string>();
@@ -620,16 +540,18 @@ namespace ServiceLib.Common
foreach (var host in hostsList)
{
if (host.StartsWith("#")) continue;
if (host.StartsWith("#"))
continue;
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (hostItem.Length < 2) continue;
systemHosts.Add(hostItem[1], hostItem[0]);
if (hostItem.Length != 2)
continue;
systemHosts.Add(hostItem.Last(), hostItem.First());
}
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return systemHosts;
@@ -677,10 +599,44 @@ namespace ServiceLib.Common
#region TempPath
public static bool HasWritePermission()
{
try
{
var basePath = GetBaseDirectory();
//When this file exists, it is equivalent to having no permission to read and write
if (File.Exists(Path.Combine(basePath, "NotStoreConfigHere.txt")))
{
return false;
}
//Check if it is installed by Windows WinGet
if (IsWindows() && basePath.Contains("Users") && basePath.Contains("WinGet"))
{
return false;
}
var tempPath = Path.Combine(basePath, "guiTemps");
if (!Directory.Exists(tempPath))
{
Directory.CreateDirectory(tempPath);
}
var fileName = Path.Combine(tempPath, GetGuid());
File.Create(fileName).Close();
File.Delete(fileName);
}
catch (Exception)
{
return false;
}
return true;
}
public static string GetPath(string fileName)
{
var startupPath = StartupPath();
if (IsNullOrEmpty(fileName))
if (fileName.IsNullOrEmpty())
{
return startupPath;
}
@@ -688,6 +644,11 @@ namespace ServiceLib.Common
return Path.Combine(startupPath, fileName);
}
public static string GetBaseDirectory(string fileName = "")
{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
}
public static string GetExePath()
{
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
@@ -695,7 +656,12 @@ namespace ServiceLib.Common
public static string StartupPath()
{
return AppDomain.CurrentDomain.BaseDirectory;
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "v2rayN");
}
return GetBaseDirectory();
}
public static string GetTempPath(string filename = "")
@@ -706,7 +672,7 @@ namespace ServiceLib.Common
Directory.CreateDirectory(tempPath);
}
if (IsNullOrEmpty(filename))
if (filename.IsNullOrEmpty())
{
return tempPath;
}
@@ -735,7 +701,7 @@ namespace ServiceLib.Common
Directory.CreateDirectory(tempPath);
}
if (Utils.IsNullOrEmpty(filename))
if (filename.IsNullOrEmpty())
{
return tempPath;
}
@@ -762,7 +728,7 @@ namespace ServiceLib.Common
}
}
if (IsNullOrEmpty(filename))
if (filename.IsNullOrEmpty())
{
return tempPath;
}
@@ -780,7 +746,7 @@ namespace ServiceLib.Common
Directory.CreateDirectory(tempPath);
}
if (Utils.IsNullOrEmpty(filename))
if (filename.IsNullOrEmpty())
{
return tempPath;
}
@@ -798,7 +764,25 @@ namespace ServiceLib.Common
Directory.CreateDirectory(tempPath);
}
if (Utils.IsNullOrEmpty(filename))
if (filename.IsNullOrEmpty())
{
return tempPath;
}
else
{
return Path.Combine(tempPath, filename);
}
}
public static string GetBinConfigPath(string filename = "")
{
var tempPath = Path.Combine(StartupPath(), "binConfigs");
if (!Directory.Exists(tempPath))
{
Directory.CreateDirectory(tempPath);
}
if (filename.IsNullOrEmpty())
{
return tempPath;
}
@@ -818,6 +802,8 @@ namespace ServiceLib.Common
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static bool IsNonWindows() => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static string GetExeName(string name)
{
return IsWindows() ? $"{name}.exe" : name;
@@ -829,38 +815,43 @@ namespace ServiceLib.Common
{
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
}
else
{
var id = GetLinuxUserId().Result ?? "1000";
if (int.TryParse(id, out var userId))
{
return userId == 0;
}
else
{
return false;
}
}
return false;
//else
//{
// var id = GetLinuxUserId().Result ?? "1000";
// if (int.TryParse(id, out var userId))
// {
// return userId == 0;
// }
// else
// {
// return false;
// }
//}
}
private static async Task<string?> GetLinuxUserId()
{
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)
{
if (fileName.IsNullOrEmpty()) return null;
if (fileName.IsNullOrEmpty())
return null;
if (fileName.Contains(' '))
fileName = fileName.AppendQuotes();
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
return await GetCliWrapOutput("/bin/bash", arg);
return await GetCliWrapOutput(Global.LinuxBash, arg);
}
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 : family" };
return await GetCliWrapOutput("/bin/bash", arg);
return await GetCliWrapOutput(Global.LinuxBash, arg);
}
public static string? GetHomePath()
@@ -872,4 +863,4 @@ namespace ServiceLib.Common
#endregion Platform
}
}
}

View File

@@ -1,9 +1,13 @@
using Microsoft.Win32;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Win32;
namespace ServiceLib.Common
{
internal static class WindowsUtils
{
private static readonly string _tag = "WindowsUtils";
public static string? RegReadValue(string path, string name, string def)
{
RegistryKey? regKey = null;
@@ -11,11 +15,11 @@ namespace ServiceLib.Common
{
regKey = Registry.CurrentUser.OpenSubKey(path, false);
var value = regKey?.GetValue(name) as string;
return Utils.IsNullOrEmpty(value) ? def : value;
return value.IsNullOrEmpty() ? def : value;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
finally
{
@@ -30,7 +34,7 @@ namespace ServiceLib.Common
try
{
regKey = Registry.CurrentUser.CreateSubKey(path);
if (Utils.IsNullOrEmpty(value.ToString()))
if (value.ToString().IsNullOrEmpty())
{
regKey?.DeleteValue(name, false);
}
@@ -41,12 +45,30 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
finally
{
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 @@
using YamlDotNet.Core;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
{
public class YamlUtils
{
private static readonly string _tag = "YamlUtils";
#region YAML
/// <summary>
@@ -26,7 +28,7 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog("FromYaml", ex);
Logging.SaveLog(_tag, ex);
return deserializer.Deserialize<T>("");
}
}
@@ -53,16 +55,13 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return result;
}
public static string? PreprocessYaml(string str)
{
var deserializer = new DeserializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.Build();
try
{
var mergingParser = new MergingParser(new Parser(new StringReader(str)));
@@ -71,11 +70,11 @@ namespace ServiceLib.Common
}
catch (Exception ex)
{
Logging.SaveLog("PreprocessYaml", ex);
Logging.SaveLog(_tag, ex);
return null;
}
}
#endregion YAML
}
}
}

View File

@@ -1,23 +1,19 @@
namespace ServiceLib.Enums
namespace ServiceLib.Enums
{
public enum ECoreType
{
v2fly = 1,
Xray = 2,
//SagerNet = 3,
v2fly_v5 = 4,
//clash = 11,
//clash_meta = 12,
mihomo = 13,
hysteria = 21,
naiveproxy = 22,
tuic = 23,
sing_box = 24,
juicity = 25,
hysteria2 = 26,
brook = 27,
overtls = 28,
v2rayN = 99
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
namespace ServiceLib.Enums
{
public enum ETheme
{
FollowSystem,
Dark,
Light,
Aquatic,
Desert,
Dusk,
NightSky
}
}

View File

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

View File

@@ -1,4 +1,4 @@
namespace ServiceLib
namespace ServiceLib
{
public class Global
{
@@ -7,25 +7,16 @@
public const string AppName = "v2rayN";
public const string GithubUrl = "https://github.com";
public const string GithubApiUrl = "https://api.github.com/repos";
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
public const string 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 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 IPAPIUrl = "https://api.ip.sb/geoip";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json";
public const string CoreConfigFileName = "config.json";
public const string CorePreConfigFileName = "configPre.json";
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
public const string CoreSpeedtestConfigFileName = "configTest{0}.json";
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
public const string ClashMixinConfigFileName = "Mixin.yaml";
@@ -46,6 +37,9 @@
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
public const string PacFileName = NamespaceSample + "pac";
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp";
@@ -61,81 +55,98 @@
public const string HttpProtocol = "http://";
public const string HttpsProtocol = "https://";
public const string SocksProtocol = "socks://";
public const string Socks5Protocol = "socks5://";
public const string UserEMail = "t@t.tt";
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
public const string AutoRunName = "v2rayNAutoRun";
public const string CustomIconName = "v2rayN.ico";
public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
public const string SystemProxyExceptionsWindows = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
public const string SystemProxyExceptionsLinux = "localhost,127.0.0.0/8,::1";
public const string RoutingRuleComma = "<COMMA>";
public const string GrpcGunMode = "gun";
public const string GrpcMultiMode = "multi";
public const int MaxPort = 65536;
public const string DelayUnit = "";
public const string SpeedUnit = "";
public const int MinFontSize = 10;
public const int MinFontSize = 8;
public const string RebootAs = "rebootas";
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() {
"{ip}:{http_port}",
"socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
""
};
public static readonly List<string> IEProxyProtocols =
[
"{ip}:{http_port}",
"socks={ip}:{socks_port}",
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
""
];
public static readonly List<string> SubConvertUrls = new List<string> {
@"https://sub.xeton.dev/sub?url={0}",
@"https://api.dler.io/sub?url={0}",
@"http://127.0.0.1:25500/sub?url={0}",
""
};
public static readonly List<string> SubConvertUrls =
[
@"https://sub.xeton.dev/sub?url={0}",
@"https://api.dler.io/sub?url={0}",
@"http://127.0.0.1:25500/sub?url={0}",
""
];
public static readonly List<string> SubConvertConfig = new List<string> {
@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
};
public static readonly List<string> SubConvertConfig =
[@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"];
public static readonly List<string> SubConvertTargets = new List<string> {
"",
"mixed",
"v2ray",
"clash",
"ss",
};
public static readonly List<string> SubConvertTargets =
[
"",
"mixed",
"v2ray",
"clash",
"ss"
];
public static readonly List<string> SpeedTestUrls = new() {
@"https://speed.cloudflare.com/__down?bytes=100000000",
@"https://speed.cloudflare.com/__down?bytes=50000000",
@"https://speed.cloudflare.com/__down?bytes=10000000",
public static readonly List<string> SpeedTestUrls =
[
@"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.gstatic.com/generate_204",
@"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://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/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/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/Chocolate4U/Iran-v2ray-rules@main/v2rayN/"
];
public static readonly Dictionary<string, string> UserAgentTexts = new()
{
@@ -150,67 +161,363 @@
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
{
{EConfigType.VMess,"vmess://"},
{EConfigType.Shadowsocks,"ss://"},
{EConfigType.SOCKS,"socks://"},
{EConfigType.VLESS,"vless://"},
{EConfigType.Trojan,"trojan://"},
{EConfigType.Hysteria2,"hysteria2://"},
{EConfigType.TUIC,"tuic://"},
{EConfigType.WireGuard,"wireguard://"}
{ EConfigType.VMess, "vmess://" },
{ EConfigType.Shadowsocks, "ss://" },
{ EConfigType.SOCKS, "socks://" },
{ EConfigType.VLESS, "vless://" },
{ EConfigType.Trojan, "trojan://" },
{ EConfigType.Hysteria2, "hysteria2://" },
{ EConfigType.TUIC, "tuic://" },
{ EConfigType.WireGuard, "wireguard://" }
};
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
{
{EConfigType.VMess,"vmess"},
{EConfigType.Shadowsocks,"shadowsocks"},
{EConfigType.SOCKS,"socks"},
{EConfigType.HTTP,"http"},
{EConfigType.VLESS,"vless"},
{EConfigType.Trojan,"trojan"},
{EConfigType.Hysteria2,"hysteria2"},
{EConfigType.TUIC,"tuic"},
{EConfigType.WireGuard,"wireguard"}
{ EConfigType.VMess, "vmess" },
{ EConfigType.Shadowsocks, "shadowsocks" },
{ EConfigType.SOCKS, "socks" },
{ EConfigType.HTTP, "http" },
{ EConfigType.VLESS, "vless" },
{ EConfigType.Trojan, "trojan" },
{ EConfigType.Hysteria2, "hysteria2" },
{ EConfigType.TUIC, "tuic" },
{ EConfigType.WireGuard, "wireguard" }
};
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
public static readonly List<string> SsSecuritiesInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" };
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
public static readonly List<string> CoreTypes = new() { "v2fly", "Xray", "sing_box" };
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
public static readonly List<string> VmessSecurities =
[
"aes-128-gcm",
"chacha20-poly1305",
"auto",
"none",
"zero"
];
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
public static readonly List<string> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" };
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"];
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"];
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" };
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
public static readonly List<string> SsSecurities =
[
"aes-256-gcm",
"aes-128-gcm",
"chacha20-poly1305",
"chacha20-ietf-poly1305",
"none",
"plain"
];
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" };
public static readonly List<string> notAllowTestType = new List<string> { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" };
public static readonly List<string> SsSecuritiesInXray =
[
"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",
"dns"
];
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
}
}
}

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler
namespace ServiceLib.Handler
{
public sealed class AppHandler
{
@@ -27,7 +27,7 @@
get
{
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
return _statePort2.Value;
return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
}
}
@@ -46,11 +46,18 @@
public bool InitApp()
{
_config = ConfigHandler.LoadConfig();
if (_config == null)
if (Utils.HasWritePermission() == false)
{
Environment.SetEnvironmentVariable(Global.LocalAppData, "1", EnvironmentVariableTarget.Process);
}
Logging.Setup();
var config = ConfigHandler.LoadConfig();
if (config == null)
{
return false;
}
_config = config;
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
//Under Win10
@@ -70,15 +77,19 @@
public bool InitComponents()
{
Logging.Setup();
Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
Logging.ClearLogs();
return true;
}
public bool Reset()
{
_statePort = null;
_statePort2 = null;
return true;
}
#endregion Init
#region Config
@@ -94,7 +105,13 @@
if (Utils.IsWindows())
{
_processJob ??= new();
_processJob?.AddProcess(processHandle);
try
{
_processJob?.AddProcess(processHandle);
}
catch
{
}
}
}
@@ -107,14 +124,14 @@
return await SQLiteHelper.Instance.TableAsync<SubItem>().OrderBy(t => t.Sort).ToListAsync();
}
public async Task<SubItem?> GetSubItem(string subid)
public async Task<SubItem?> GetSubItem(string? subid)
{
return await SQLiteHelper.Instance.TableAsync<SubItem>().FirstOrDefaultAsync(t => t.Id == subid);
}
public async Task<List<ProfileItem>?> ProfileItems(string subid)
{
if (Utils.IsNullOrEmpty(subid))
if (subid.IsNullOrEmpty())
{
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().ToListAsync();
}
@@ -136,11 +153,11 @@
from ProfileItem a
left join SubItem b on a.subid = b.id
where 1=1 ";
if (Utils.IsNotEmpty(subid))
if (subid.IsNotEmpty())
{
sql += $" and a.subid = '{subid}'";
}
if (Utils.IsNotEmpty(filter))
if (filter.IsNotEmpty())
{
if (filter.Contains('\''))
{
@@ -152,48 +169,9 @@
return await SQLiteHelper.Instance.QueryAsync<ProfileItemModel>(sql);
}
public async Task<List<ProfileItemModel>?> ProfileItemsEx(string subid, string filter)
{
var lstModel = await ProfileItems(_config.SubIndexId, filter);
await ConfigHandler.SetDefaultServer(_config, lstModel);
var lstServerStat = (_config.GuiItem.EnableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
lstModel = (from t in lstModel
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
IndexId = t.IndexId,
ConfigType = t.ConfigType,
Remarks = t.Remarks,
Address = t.Address,
Port = t.Port,
Security = t.Security,
Network = t.Network,
StreamSecurity = t.StreamSecurity,
Subid = t.Subid,
SubRemarks = t.SubRemarks,
IsActive = t.IndexId == _config.IndexId,
Sort = t33 == null ? 0 : t33.Sort,
Delay = t33 == null ? 0 : t33.Delay,
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay} {Global.DelayUnit}" : string.Empty,
SpeedVal = t33?.Speed != 0 ? $"{t33?.Speed} {Global.SpeedUnit}" : string.Empty,
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
TotalUp = t22 == null ? "" : Utils.HumanFy(t22.TotalUp)
}).OrderBy(t => t.Sort).ToList();
return lstModel;
}
public async Task<ProfileItem?> GetProfileItem(string indexId)
{
if (Utils.IsNullOrEmpty(indexId))
if (indexId.IsNullOrEmpty())
{
return null;
}
@@ -202,7 +180,7 @@
public async Task<ProfileItem?> GetProfileItemViaRemarks(string? remarks)
{
if (Utils.IsNullOrEmpty(remarks))
if (remarks.IsNullOrEmpty())
{
return null;
}
@@ -211,12 +189,12 @@
public async Task<List<RoutingItem>?> RoutingItems()
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(it => it.Locked == false).OrderBy(t => t.Sort).ToListAsync();
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().OrderBy(t => t.Sort).ToListAsync();
}
public async Task<RoutingItem?> GetRoutingItem(string id)
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Locked == false && it.Id == id);
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Id == id);
}
public async Task<List<DNSItem>?> DNSItems()
@@ -247,7 +225,7 @@
case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox;
}
return Global.SsSecuritiesInSagerNet;
return Global.SsSecuritiesInSingbox;
}
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)
@@ -257,18 +235,10 @@
return (ECoreType)profileItem.CoreType;
}
if (_config.CoreTypeItem == null)
{
return ECoreType.Xray;
}
var item = _config.CoreTypeItem.FirstOrDefault(it => it.ConfigType == eConfigType);
if (item == null)
{
return ECoreType.Xray;
}
return item.CoreType;
var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType);
return item?.CoreType ?? ECoreType.Xray;
}
#endregion Core Type
}
}
}

View File

@@ -1,10 +1,12 @@
using System.Security.Principal;
using System.Security.Principal;
using System.Text.RegularExpressions;
namespace ServiceLib.Handler
{
public static class AutoStartupHandler
{
private static readonly string _tag = "AutoStartupHandler";
public static async Task<bool> UpdateTask(Config config)
{
if (Utils.IsWindows())
@@ -25,6 +27,15 @@ namespace ServiceLib.Handler
await SetTaskLinux();
}
}
else if (Utils.IsOSX())
{
await ClearTaskOSX();
if (config.GuiItem.AutoRun)
{
await SetTaskOSX();
}
}
return true;
}
@@ -39,6 +50,8 @@ namespace ServiceLib.Handler
{
AutoStartTaskService(autoRunName, "", "");
}
await Task.CompletedTask;
}
private static async Task SetTaskWindows()
@@ -58,8 +71,9 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
await Task.CompletedTask;
}
/// <summary>
@@ -71,7 +85,7 @@ namespace ServiceLib.Handler
/// <exception cref="ArgumentNullException"></exception>
public static void AutoStartTaskService(string taskName, string fileName, string description)
{
if (Utils.IsNullOrEmpty(taskName))
if (taskName.IsNullOrEmpty())
{
return;
}
@@ -79,7 +93,7 @@ namespace ServiceLib.Handler
var logonUser = WindowsIdentity.GetCurrent().Name;
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
if (Utils.IsNullOrEmpty(fileName))
if (fileName.IsNullOrEmpty())
{
foreach (var t in tasks)
{
@@ -95,7 +109,7 @@ namespace ServiceLib.Handler
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(30) });
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
@@ -119,15 +133,16 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
await Task.CompletedTask;
}
private static async Task SetTaskLinux()
{
try
{
var linuxConfig = Utils.GetEmbedText(Global.LinuxAutostartConfig);
var linuxConfig = EmbedUtils.GetEmbedText(Global.LinuxAutostartConfig);
if (linuxConfig.IsNotEmpty())
{
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
@@ -139,7 +154,7 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
@@ -151,5 +166,77 @@ namespace ServiceLib.Handler
}
#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
{
@@ -7,12 +7,13 @@ namespace ServiceLib.Handler
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
public static ClashApiHandler Instance => instance.Value;
private static readonly string _tag = "ClashApiHandler";
private Dictionary<string, ProxiesItem>? _proxies;
public Dictionary<string, object> ProfileContent { get; set; }
public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync(Config config)
public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync()
{
for (var i = 0; i < 5; i++)
for (var i = 0; i < 3; i++)
{
var url = $"{GetApiUrl()}/proxies";
var result = await HttpClientHelper.Instance.TryGetAsync(url);
@@ -36,64 +37,55 @@ namespace ServiceLib.Handler
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
{
Task.Run(() =>
{
if (blAll)
Task.Run(async () =>
{
for (int i = 0; i < 5; i++)
if (blAll)
{
if (_proxies != null)
if (_proxies == null)
{
break;
await GetClashProxiesAsync();
}
lstProxy = new List<ClashProxyModel>();
foreach (var kv in _proxies ?? [])
{
if (Global.notAllowTestType.Contains(kv.Value.type?.ToLower()))
{
continue;
}
lstProxy.Add(new ClashProxyModel()
{
Name = kv.Value.name,
Type = kv.Value.type?.ToLower(),
});
}
Task.Delay(5000).Wait();
}
if (_proxies == null)
if (lstProxy is not { Count: > 0 })
{
return;
}
lstProxy = new List<ClashProxyModel>();
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies)
var urlBase = $"{GetApiUrl()}/proxies";
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
var tasks = new List<Task>();
foreach (var it in lstProxy)
{
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
if (Global.notAllowTestType.Contains(it.Type.ToLower()))
{
continue;
}
lstProxy.Add(new ClashProxyModel()
var name = it.Name;
var url = string.Format(urlBase, name);
tasks.Add(Task.Run(async () =>
{
Name = kv.Value.name,
Type = kv.Value.type.ToLower(),
});
var result = await HttpClientHelper.Instance.TryGetAsync(url);
updateFunc?.Invoke(it, result);
}));
}
}
if (lstProxy == null)
{
return;
}
var urlBase = $"{GetApiUrl()}/proxies";
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
List<Task> tasks = new List<Task>();
foreach (var it in lstProxy)
{
if (Global.notAllowTestType.Contains(it.Type.ToLower()))
{
continue;
}
var name = it.Name;
var url = string.Format(urlBase, name);
tasks.Add(Task.Run(async () =>
{
var result = await HttpClientHelper.Instance.TryGetAsync(url);
updateFunc?.Invoke(it, result);
}));
}
Task.WaitAll(tasks.ToArray());
Task.Delay(1000).Wait();
updateFunc?.Invoke(null, "");
});
await Task.WhenAll(tasks);
await Task.Delay(1000);
updateFunc?.Invoke(null, "");
});
}
public List<ProxiesItem>? GetClashProxyGroups()
@@ -109,7 +101,7 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog("GetClashProxyGroups", ex);
Logging.SaveLog(_tag, ex);
return null;
}
}
@@ -119,13 +111,13 @@ namespace ServiceLib.Handler
try
{
var url = $"{GetApiUrl()}/proxies/{name}";
Dictionary<string, string> headers = new Dictionary<string, string>();
var headers = new Dictionary<string, string>();
headers.Add("name", nameNode);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
@@ -147,17 +139,17 @@ namespace ServiceLib.Handler
try
{
var url = $"{GetApiUrl()}/configs?force=true";
Dictionary<string, string> headers = new Dictionary<string, string>();
var headers = new Dictionary<string, string>();
headers.Add("path", filePath);
await HttpClientHelper.Instance.PutAsync(url, headers);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
public async Task<ClashConnections?> GetClashConnectionsAsync(Config config)
public async Task<ClashConnections?> GetClashConnectionsAsync()
{
try
{
@@ -169,7 +161,7 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
return null;
@@ -184,7 +176,7 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
@@ -193,4 +185,4 @@ namespace ServiceLib.Handler
return $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort2}";
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Text.RegularExpressions;
namespace ServiceLib.Handler
@@ -9,7 +9,7 @@ namespace ServiceLib.Handler
public class ConfigHandler
{
private static readonly string _configRes = Global.ConfigFileName;
private static readonly object _objLock = new();
private static readonly string _tag = "ConfigHandler";
#region ConfigHandler
@@ -21,8 +21,8 @@ namespace ServiceLib.Handler
public static Config? LoadConfig()
{
Config? config = null;
var result = Utils.LoadResource(Utils.GetConfigPath(_configRes));
if (Utils.IsNotEmpty(result))
var result = EmbedUtils.LoadResource(Utils.GetConfigPath(_configRes));
if (result.IsNotEmpty())
{
config = JsonUtils.Deserialize<Config>(result);
}
@@ -62,17 +62,14 @@ namespace ServiceLib.Handler
{
if (config.Inbound.Count > 0)
{
config.Inbound[0].Protocol = EInboundProtocol.socks.ToString();
config.Inbound.First().Protocol = EInboundProtocol.socks.ToString();
}
}
config.RoutingBasicItem ??= new()
{
EnableRoutingAdvanced = true
};
if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy))
config.RoutingBasicItem ??= new();
if (config.RoutingBasicItem.DomainStrategy.IsNullOrEmpty())
{
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies[0];//"IPIfNonMatch";
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();
}
config.KcpItem ??= new KcpItem
@@ -97,10 +94,7 @@ namespace ServiceLib.Handler
EnableTun = false,
Mtu = 9000,
};
config.GuiItem ??= new()
{
EnableStatistics = false,
};
config.GuiItem ??= new();
config.MsgUIItem ??= new();
config.UiItem ??= new UIItem()
@@ -109,37 +103,32 @@ namespace ServiceLib.Handler
};
config.UiItem.MainColumnItem ??= new();
if (Utils.IsNullOrEmpty(config.UiItem.CurrentLanguage))
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
{
if (Thread.CurrentThread.CurrentCulture.Name.Equals("zh-cn", StringComparison.CurrentCultureIgnoreCase))
{
config.UiItem.CurrentLanguage = Global.Languages[0];
}
else
{
config.UiItem.CurrentLanguage = Global.Languages[2];
}
config.UiItem.CurrentLanguage = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.Equals("zh", StringComparison.CurrentCultureIgnoreCase)
? Global.Languages.First()
: Global.Languages[2];
}
config.ConstItem ??= new ConstItem();
if (Utils.IsNullOrEmpty(config.ConstItem.DefIEProxyExceptions))
{
config.ConstItem.DefIEProxyExceptions = Global.IEProxyExceptions;
}
config.SpeedTestItem ??= new();
if (config.SpeedTestItem.SpeedTestTimeout < 10)
{
config.SpeedTestItem.SpeedTestTimeout = 10;
}
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedTestUrl))
if (config.SpeedTestItem.SpeedTestUrl.IsNullOrEmpty())
{
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls[0];
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls.First();
}
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedPingTestUrl))
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
{
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
}
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
{
config.SpeedTestItem.MixedConcurrencyCount = 5;
}
config.Mux4RayItem ??= new()
{
@@ -150,7 +139,7 @@ namespace ServiceLib.Handler
config.Mux4SboxItem ??= new()
{
Protocol = Global.SingboxMuxs[0],
Protocol = Global.SingboxMuxs.First(),
MaxConnections = 8
};
@@ -163,6 +152,18 @@ namespace ServiceLib.Handler
config.SystemProxyItem ??= new();
config.WebDavItem ??= new();
config.CheckUpdateItem ??= new();
config.Fragment4RayItem ??= new()
{
Packets = "tlshello",
Length = "100-200",
Interval = "10-20"
};
config.GlobalHotkeys ??= new();
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
{
config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux;
}
return config;
}
@@ -174,30 +175,26 @@ namespace ServiceLib.Handler
/// <returns></returns>
public static async Task<int> SaveConfig(Config config)
{
lock (_objLock)
try
{
try
{
//save temp file
var resPath = Utils.GetConfigPath(_configRes);
var tempPath = $"{resPath}_temp";
if (JsonUtils.ToFile(config, tempPath) != 0)
{
return -1;
}
//save temp file
var resPath = Utils.GetConfigPath(_configRes);
var tempPath = $"{resPath}_temp";
if (File.Exists(resPath))
{
File.Delete(resPath);
}
//rename
File.Move(tempPath, resPath);
}
catch (Exception ex)
var content = JsonUtils.Serialize(config, true, true);
if (content.IsNullOrEmpty())
{
Logging.SaveLog("ToJsonFile", ex);
return -1;
}
await File.WriteAllTextAsync(tempPath, content);
//rename
File.Move(tempPath, resPath, true);
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
return -1;
}
return 0;
@@ -220,6 +217,7 @@ namespace ServiceLib.Handler
item.Remarks = profileItem.Remarks;
item.Address = profileItem.Address;
item.Port = profileItem.Port;
item.Ports = profileItem.Ports;
item.Id = profileItem.Id;
item.AlterId = profileItem.AlterId;
@@ -240,6 +238,7 @@ namespace ServiceLib.Handler
item.PublicKey = profileItem.PublicKey;
item.ShortId = profileItem.ShortId;
item.SpiderX = profileItem.SpiderX;
item.Extra = profileItem.Extra;
}
var ret = item.ConfigType switch
@@ -297,7 +296,7 @@ namespace ServiceLib.Handler
/// <param name="config"></param>
/// <param name="indexes"></param>
/// <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";
foreach (var item in indexes)
@@ -306,7 +305,7 @@ namespace ServiceLib.Handler
}
await SQLiteHelper.Instance.UpdateAllAsync(indexes);
await RemoveServerViaSubid(config, subid, false);
await RemoveServersViaSubid(config, subid, false);
return 0;
}
@@ -355,7 +354,7 @@ namespace ServiceLib.Handler
/// <returns></returns>
public static async Task<int> SetDefaultServerIndex(Config config, string? indexId)
{
if (Utils.IsNullOrEmpty(indexId))
if (indexId.IsNullOrEmpty())
{
return -1;
}
@@ -384,7 +383,7 @@ namespace ServiceLib.Handler
}
var item = await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(t => t.Port > 0);
return await SetDefaultServerIndex(config, item.IndexId);
return await SetDefaultServerIndex(config, item?.IndexId);
}
public static async Task<ProfileItem?> GetDefaultServer(Config config)
@@ -430,7 +429,7 @@ namespace ServiceLib.Handler
{
return 0;
}
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].IndexId) - 1;
sort = ProfileExHandler.Instance.GetSort(lstProfile.First().IndexId) - 1;
break;
}
@@ -466,12 +465,12 @@ namespace ServiceLib.Handler
break;
}
case EMove.Position:
sort = pos * 10 + 1;
sort = (pos * 10) + 1;
break;
}
ProfileExHandler.Instance.SetSort(lstProfile[index].IndexId, sort);
return 0;
return await Task.FromResult(0);
}
/// <summary>
@@ -501,13 +500,13 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return -1;
}
profileItem.Address = newFileName;
profileItem.ConfigType = EConfigType.Custom;
if (Utils.IsNullOrEmpty(profileItem.Remarks))
if (profileItem.Remarks.IsNullOrEmpty())
{
profileItem.Remarks = $"import custom@{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}";
}
@@ -625,7 +624,7 @@ namespace ServiceLib.Handler
profileItem.Address = profileItem.Address.TrimEx();
profileItem.Id = profileItem.Id.TrimEx();
if (Utils.IsNullOrEmpty(profileItem.StreamSecurity))
if (profileItem.StreamSecurity.IsNullOrEmpty())
{
profileItem.StreamSecurity = Global.StreamSecurity;
}
@@ -655,7 +654,7 @@ namespace ServiceLib.Handler
profileItem.Path = profileItem.Path.TrimEx();
profileItem.Network = string.Empty;
if (Utils.IsNullOrEmpty(profileItem.StreamSecurity))
if (profileItem.StreamSecurity.IsNullOrEmpty())
{
profileItem.StreamSecurity = Global.StreamSecurity;
}
@@ -690,11 +689,11 @@ namespace ServiceLib.Handler
profileItem.HeaderType = Global.TuicCongestionControls.FirstOrDefault()!;
}
if (Utils.IsNullOrEmpty(profileItem.StreamSecurity))
if (profileItem.StreamSecurity.IsNullOrEmpty())
{
profileItem.StreamSecurity = Global.StreamSecurity;
}
if (Utils.IsNullOrEmpty(profileItem.Alpn))
if (profileItem.Alpn.IsNullOrEmpty())
{
profileItem.Alpn = "h3";
}
@@ -727,7 +726,7 @@ namespace ServiceLib.Handler
profileItem.Network = string.Empty;
if (profileItem.ShortId.IsNullOrEmpty())
{
profileItem.ShortId = Global.TunMtus.FirstOrDefault();
profileItem.ShortId = Global.TunMtus.First().ToString();
}
if (profileItem.Id.IsNullOrEmpty())
@@ -761,75 +760,72 @@ namespace ServiceLib.Handler
Security = t.Security,
Network = t.Network,
StreamSecurity = t.StreamSecurity,
Delay = t33 == null ? 0 : t33.Delay,
Speed = t33 == null ? 0 : t33.Speed,
Sort = t33 == null ? 0 : t33.Sort
Delay = t33?.Delay ?? 0,
Speed = t33?.Speed ?? 0,
Sort = t33?.Sort ?? 0
}).ToList();
Enum.TryParse(colName, true, out EServerColName name);
var propertyName = string.Empty;
switch (name)
{
case EServerColName.ConfigType:
case EServerColName.Remarks:
case EServerColName.Address:
case EServerColName.Port:
case EServerColName.Network:
case EServerColName.StreamSecurity:
propertyName = name.ToString();
break;
case EServerColName.DelayVal:
propertyName = "Delay";
break;
case EServerColName.SpeedVal:
propertyName = "Speed";
break;
case EServerColName.SubRemarks:
propertyName = "Subid";
break;
default:
return -1;
}
var items = lstProfile.AsQueryable();
if (asc)
{
lstProfile = items.OrderBy(propertyName).ToList();
lstProfile = name switch
{
EServerColName.ConfigType => lstProfile.OrderBy(t => t.ConfigType).ToList(),
EServerColName.Remarks => lstProfile.OrderBy(t => t.Remarks).ToList(),
EServerColName.Address => lstProfile.OrderBy(t => t.Address).ToList(),
EServerColName.Port => lstProfile.OrderBy(t => t.Port).ToList(),
EServerColName.Network => lstProfile.OrderBy(t => t.Network).ToList(),
EServerColName.StreamSecurity => lstProfile.OrderBy(t => t.StreamSecurity).ToList(),
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
_ => lstProfile
};
}
else
{
lstProfile = items.OrderByDescending(propertyName).ToList();
lstProfile = name switch
{
EServerColName.ConfigType => lstProfile.OrderByDescending(t => t.ConfigType).ToList(),
EServerColName.Remarks => lstProfile.OrderByDescending(t => t.Remarks).ToList(),
EServerColName.Address => lstProfile.OrderByDescending(t => t.Address).ToList(),
EServerColName.Port => lstProfile.OrderByDescending(t => t.Port).ToList(),
EServerColName.Network => lstProfile.OrderByDescending(t => t.Network).ToList(),
EServerColName.StreamSecurity => lstProfile.OrderByDescending(t => t.StreamSecurity).ToList(),
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
_ => lstProfile
};
}
for (int i = 0; i < lstProfile.Count; i++)
for (var i = 0; i < lstProfile.Count; i++)
{
ProfileExHandler.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10);
}
if (name == EServerColName.DelayVal)
switch (name)
{
var maxSort = lstProfile.Max(t => t.Sort) + 10;
foreach (var item in lstProfile)
{
if (item.Delay <= 0)
case EServerColName.DelayVal:
{
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
var maxSort = lstProfile.Max(t => t.Sort) + 10;
foreach (var item in lstProfile.Where(item => item.Delay <= 0))
{
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
}
break;
}
}
}
if (name == EServerColName.SpeedVal)
{
var maxSort = lstProfile.Max(t => t.Sort) + 10;
foreach (var item in lstProfile)
{
if (item.Speed <= 0)
case EServerColName.SpeedVal:
{
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
var maxSort = lstProfile.Max(t => t.Sort) + 10;
foreach (var item in lstProfile.Where(item => item.Speed <= 0))
{
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
}
break;
}
}
}
return 0;
@@ -862,7 +858,7 @@ namespace ServiceLib.Handler
{
return -1;
}
if (Utils.IsNotEmpty(profileItem.Security) && profileItem.Security != Global.None)
if (profileItem.Security.IsNotEmpty() && profileItem.Security != Global.None)
{
profileItem.Security = Global.None;
}
@@ -875,12 +871,19 @@ namespace ServiceLib.Handler
public static async Task<Tuple<int, int>> DedupServerList(Config config, string subId)
{
var lstProfile = await AppHandler.Instance.ProfileItems(subId);
if (lstProfile == null)
{
return new Tuple<int, int>(0, 0);
}
List<ProfileItem> lstKeep = new();
List<ProfileItem> lstRemove = new();
if (!config.GuiItem.KeepOlderDedupl) lstProfile.Reverse();
if (!config.GuiItem.KeepOlderDedupl)
{
lstProfile.Reverse();
}
foreach (ProfileItem item in lstProfile)
foreach (var item in lstProfile)
{
if (!lstKeep.Exists(i => CompareProfileItem(i, item, false)))
{
@@ -891,7 +894,7 @@ namespace ServiceLib.Handler
lstRemove.Add(item);
}
}
await RemoveServer(config, lstRemove);
await RemoveServers(config, lstRemove);
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
}
@@ -900,7 +903,7 @@ namespace ServiceLib.Handler
{
profileItem.ConfigVersion = 2;
if (Utils.IsNotEmpty(profileItem.StreamSecurity))
if (profileItem.StreamSecurity.IsNotEmpty())
{
if (profileItem.StreamSecurity != Global.StreamSecurity
&& profileItem.StreamSecurity != Global.StreamSecurityReality)
@@ -909,24 +912,24 @@ namespace ServiceLib.Handler
}
else
{
if (Utils.IsNullOrEmpty(profileItem.AllowInsecure))
if (profileItem.AllowInsecure.IsNullOrEmpty())
{
profileItem.AllowInsecure = config.CoreBasicItem.DefAllowInsecure.ToString().ToLower();
}
if (Utils.IsNullOrEmpty(profileItem.Fingerprint) && profileItem.StreamSecurity == Global.StreamSecurityReality)
if (profileItem.Fingerprint.IsNullOrEmpty() && profileItem.StreamSecurity == Global.StreamSecurityReality)
{
profileItem.Fingerprint = config.CoreBasicItem.DefFingerprint;
}
}
}
if (Utils.IsNotEmpty(profileItem.Network) && !Global.Networks.Contains(profileItem.Network))
if (profileItem.Network.IsNotEmpty() && !Global.Networks.Contains(profileItem.Network))
{
profileItem.Network = Global.DefaultNetwork;
}
var maxSort = -1;
if (Utils.IsNullOrEmpty(profileItem.IndexId))
if (profileItem.IndexId.IsNullOrEmpty())
{
profileItem.IndexId = Utils.GetGuid(false);
maxSort = ProfileExHandler.Instance.GetMaxSort();
@@ -947,7 +950,7 @@ namespace ServiceLib.Handler
return 0;
}
private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks)
private static bool CompareProfileItem(ProfileItem? o, ProfileItem? n, bool remarks)
{
if (o == null || n == null)
{
@@ -955,19 +958,27 @@ namespace ServiceLib.Handler
}
return o.ConfigType == n.ConfigType
&& o.Address == n.Address
&& o.Port == n.Port
&& o.Id == n.Id
&& o.AlterId == n.AlterId
&& o.Security == n.Security
&& o.Network == n.Network
&& o.HeaderType == n.HeaderType
&& o.RequestHost == n.RequestHost
&& o.Path == n.Path
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& o.Flow == n.Flow
&& o.Sni == n.Sni
&& (!remarks || o.Remarks == n.Remarks);
&& AreEqual(o.Address, n.Address)
&& o.Port == n.Port
&& AreEqual(o.Id, n.Id)
&& AreEqual(o.Security, n.Security)
&& AreEqual(o.Network, n.Network)
&& AreEqual(o.HeaderType, n.HeaderType)
&& AreEqual(o.RequestHost, n.RequestHost)
&& AreEqual(o.Path, n.Path)
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& AreEqual(o.Flow, n.Flow)
&& AreEqual(o.Sni, n.Sni)
&& AreEqual(o.Alpn, n.Alpn)
&& AreEqual(o.Fingerprint, n.Fingerprint)
&& AreEqual(o.PublicKey, n.PublicKey)
&& AreEqual(o.ShortId, n.ShortId)
&& (!remarks || o.Remarks == n.Remarks);
static bool AreEqual(string? a, string? b)
{
return string.Equals(a, b) || (string.IsNullOrEmpty(a) && string.IsNullOrEmpty(b));
}
}
private static async Task<int> RemoveProfileItem(Config config, string indexId)
@@ -988,7 +999,7 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog("Remove Item", ex);
Logging.SaveLog(_tag, ex);
}
return 0;
@@ -1005,8 +1016,7 @@ namespace ServiceLib.Handler
return result;
}
var fileName = configPath;
if (!File.Exists(fileName))
if (!File.Exists(configPath))
{
return result;
}
@@ -1024,6 +1034,53 @@ namespace ServiceLib.Handler
return result;
}
public static async Task<ProfileItem?> GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
{
ProfileItem? itemSocks = null;
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
{
itemSocks = new ProfileItem()
{
CoreType = ECoreType.sing_box,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Sni = node.Address, //Tun2SocksAddress
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
};
}
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
{
var preCoreType = config.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
itemSocks = new ProfileItem()
{
CoreType = preCoreType,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Port = node.PreSocksPort.Value,
};
}
await Task.CompletedTask;
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
#region Batch add servers
@@ -1037,16 +1094,16 @@ namespace ServiceLib.Handler
/// <returns>成功导入的数量</returns>
private static async Task<int> AddBatchServersCommon(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
if (strData.IsNullOrEmpty())
{
return -1;
}
var subFilter = string.Empty;
//remove sub items
if (isSub && Utils.IsNotEmpty(subid))
if (isSub && subid.IsNotEmpty())
{
await RemoveServerViaSubid(config, subid, isSub);
await RemoveServersViaSubid(config, subid, isSub);
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
}
@@ -1075,7 +1132,7 @@ namespace ServiceLib.Handler
}
//exist sub items //filter
if (isSub && Utils.IsNotEmpty(subid) && Utils.IsNotEmpty(subFilter))
if (isSub && subid.IsNotEmpty() && subFilter.IsNotEmpty())
{
if (!Regex.IsMatch(profileItem.Remarks, subFilter))
{
@@ -1116,7 +1173,7 @@ namespace ServiceLib.Handler
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
if (strData.IsNullOrEmpty())
{
return -1;
}
@@ -1138,9 +1195,9 @@ namespace ServiceLib.Handler
}
if (lstProfiles != null && lstProfiles.Count > 0)
{
if (isSub && Utils.IsNotEmpty(subid))
if (isSub && subid.IsNotEmpty())
{
await RemoveServerViaSubid(config, subid, isSub);
await RemoveServersViaSubid(config, subid, isSub);
}
int count = 0;
foreach (var it in lstProfiles)
@@ -1189,14 +1246,14 @@ namespace ServiceLib.Handler
{
profileItem = NaiveproxyFmt.ResolveFull(strData, subRemarks);
}
if (profileItem is null || Utils.IsNullOrEmpty(profileItem.Address))
if (profileItem is null || profileItem.Address.IsNullOrEmpty())
{
return -1;
}
if (isSub && Utils.IsNotEmpty(subid))
if (isSub && subid.IsNotEmpty())
{
await RemoveServerViaSubid(config, subid, isSub);
await RemoveServersViaSubid(config, subid, isSub);
}
profileItem.Subid = subid;
@@ -1214,14 +1271,14 @@ namespace ServiceLib.Handler
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
if (strData.IsNullOrEmpty())
{
return -1;
}
if (isSub && Utils.IsNotEmpty(subid))
if (isSub && subid.IsNotEmpty())
{
await RemoveServerViaSubid(config, subid, isSub);
await RemoveServersViaSubid(config, subid, isSub);
}
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
@@ -1246,13 +1303,13 @@ namespace ServiceLib.Handler
public static async Task<int> AddBatchServers(Config config, string strData, string subid, bool isSub)
{
if (Utils.IsNullOrEmpty(strData))
if (strData.IsNullOrEmpty())
{
return -1;
}
List<ProfileItem>? lstOriSub = null;
ProfileItem? activeProfile = null;
if (isSub && Utils.IsNotEmpty(subid))
if (isSub && subid.IsNotEmpty())
{
lstOriSub = await AppHandler.Instance.ProfileItems(subid);
activeProfile = lstOriSub?.FirstOrDefault(t => t.IndexId == config.IndexId);
@@ -1294,6 +1351,20 @@ namespace ServiceLib.Handler
}
}
//Keep the last traffic statistics
if (lstOriSub != null)
{
var lstSub = await AppHandler.Instance.ProfileItems(subid);
foreach (var item in lstSub)
{
var existItem = lstOriSub?.FirstOrDefault(t => config.UiItem.EnableUpdateSubOnlyRemarksExist ? t.Remarks == item.Remarks : CompareProfileItem(t, item, true));
if (existItem != null)
{
await StatisticsHandler.Instance.CloneServerStatItem(existItem.IndexId, item.IndexId);
}
}
}
return counter;
}
@@ -1322,7 +1393,8 @@ namespace ServiceLib.Handler
};
var uri = Utils.TryUri(url);
if (uri == null) return -1;
if (uri == null)
return -1;
//Do not allow http protocol
if (url.StartsWith(Global.HttpProtocol) && !Utils.IsPrivateNetwork(uri.IdnHost))
{
@@ -1362,7 +1434,7 @@ namespace ServiceLib.Handler
item.Memo = subItem.Memo;
}
if (Utils.IsNullOrEmpty(item.Id))
if (item.Id.IsNullOrEmpty())
{
item.Id = Utils.GetGuid(false);
@@ -1393,9 +1465,9 @@ namespace ServiceLib.Handler
/// <param name="config"></param>
/// <param name="subid"></param>
/// <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 (subid.IsNullOrEmpty())
{
return -1;
}
@@ -1424,7 +1496,7 @@ namespace ServiceLib.Handler
return 0;
}
await SQLiteHelper.Instance.DeleteAsync(item);
await RemoveServerViaSubid(config, id, false);
await RemoveServersViaSubid(config, id, false);
return 0;
}
@@ -1446,7 +1518,7 @@ namespace ServiceLib.Handler
public static async Task<int> SaveRoutingItem(Config config, RoutingItem item)
{
if (Utils.IsNullOrEmpty(item.Id))
if (item.Id.IsNullOrEmpty())
{
item.Id = Utils.GetGuid(false);
}
@@ -1469,7 +1541,7 @@ namespace ServiceLib.Handler
/// <returns></returns>
public static async Task<int> AddBatchRoutingRules(RoutingItem routingItem, string strData)
{
if (Utils.IsNullOrEmpty(strData))
if (strData.IsNullOrEmpty())
{
return -1;
}
@@ -1487,7 +1559,7 @@ namespace ServiceLib.Handler
routingItem.RuleNum = lstRules.Count;
routingItem.RuleSet = JsonUtils.Serialize(lstRules, false);
if (Utils.IsNullOrEmpty(routingItem.Id))
if (routingItem.Id.IsNullOrEmpty())
{
routingItem.Id = Utils.GetGuid(false);
}
@@ -1576,7 +1648,7 @@ namespace ServiceLib.Handler
break;
}
}
return 0;
return await Task.FromResult(0);
}
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
@@ -1596,7 +1668,7 @@ namespace ServiceLib.Handler
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
if (item is null)
{
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(t => t.Locked == false);
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
await SetDefaultRouting(config, item2);
return item2;
}
@@ -1606,7 +1678,7 @@ namespace ServiceLib.Handler
public static async Task<int> InitRouting(Config config, bool blImportAdvancedRules = false)
{
if (string.IsNullOrEmpty(config.ConstItem.RouteRulesTemplateSourceUrl))
if (config.ConstItem.RouteRulesTemplateSourceUrl.IsNullOrEmpty())
{
await InitBuiltinRouting(config, blImportAdvancedRules);
}
@@ -1622,7 +1694,7 @@ namespace ServiceLib.Handler
{
var downloadHandle = new DownloadService();
var templateContent = await downloadHandle.TryDownloadString(config.ConstItem.RouteRulesTemplateSourceUrl, true, "");
if (string.IsNullOrEmpty(templateContent))
if (templateContent.IsNullOrEmpty())
return await InitBuiltinRouting(config, blImportAdvancedRules); // fallback
var template = JsonUtils.Deserialize<RoutingTemplate>(templateContent);
@@ -1639,14 +1711,14 @@ namespace ServiceLib.Handler
{
var item = template.RoutingItems[i];
if (string.IsNullOrEmpty(item.Url) && string.IsNullOrEmpty(item.RuleSet))
if (item.Url.IsNullOrEmpty() && item.RuleSet.IsNullOrEmpty())
continue;
var ruleSetsString = !string.IsNullOrEmpty(item.RuleSet)
var ruleSetsString = !item.RuleSet.IsNullOrEmpty()
? item.RuleSet
: await downloadHandle.TryDownloadString(item.Url, true, "");
if (string.IsNullOrEmpty(ruleSetsString))
if (ruleSetsString.IsNullOrEmpty())
continue;
item.Remarks = $"{template.Version}-{item.Remarks}";
@@ -1670,6 +1742,15 @@ namespace ServiceLib.Handler
{
var ver = "V3-";
var items = await AppHandler.Instance.RoutingItems();
//TODO Temporary code to be removed later
var lockItem = items?.FirstOrDefault(t => t.Locked == true);
if (lockItem != null)
{
await ConfigHandler.RemoveRoutingItem(lockItem);
items = await AppHandler.Instance.RoutingItems();
}
if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0)
{
return 0;
@@ -1683,7 +1764,7 @@ namespace ServiceLib.Handler
Url = string.Empty,
Sort = maxSort + 1,
};
await AddBatchRoutingRules(item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
await AddBatchRoutingRules(item2, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "white"));
//Blacklist
var item3 = new RoutingItem()
@@ -1692,7 +1773,7 @@ namespace ServiceLib.Handler
Url = string.Empty,
Sort = maxSort + 2,
};
await AddBatchRoutingRules(item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
await AddBatchRoutingRules(item3, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "black"));
//Global
var item1 = new RoutingItem()
@@ -1701,7 +1782,7 @@ namespace ServiceLib.Handler
Url = string.Empty,
Sort = maxSort + 3,
};
await AddBatchRoutingRules(item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));
await AddBatchRoutingRules(item1, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "global"));
if (!blImportAdvancedRules)
{
@@ -1710,11 +1791,6 @@ namespace ServiceLib.Handler
return 0;
}
public static async Task<RoutingItem?> GetLockedRoutingItem(Config config)
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Locked == true);
}
public static async Task RemoveRoutingItem(RoutingItem routingItem)
{
await SQLiteHelper.Instance.DeleteAsync(routingItem);
@@ -1754,7 +1830,7 @@ namespace ServiceLib.Handler
return -1;
}
if (Utils.IsNullOrEmpty(item.Id))
if (item.Id.IsNullOrEmpty())
{
item.Id = Utils.GetGuid(false);
}
@@ -1775,17 +1851,17 @@ namespace ServiceLib.Handler
var downloadHandle = new DownloadService();
var templateContent = await downloadHandle.TryDownloadString(url, true, "");
if (string.IsNullOrEmpty(templateContent))
if (templateContent.IsNullOrEmpty())
return currentItem;
var template = JsonUtils.Deserialize<DNSItem>(templateContent);
if (template == null)
return currentItem;
if (!string.IsNullOrEmpty(template.NormalDNS))
if (!template.NormalDNS.IsNullOrEmpty())
template.NormalDNS = await downloadHandle.TryDownloadString(template.NormalDNS, true, "");
if (!string.IsNullOrEmpty(template.TunDNS))
if (!template.TunDNS.IsNullOrEmpty())
template.TunDNS = await downloadHandle.TryDownloadString(template.TunDNS, true, "");
template.Id = currentItem.Id;
@@ -1822,6 +1898,16 @@ namespace ServiceLib.Handler
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json"));
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
return true;
case EPresetType.Iran:
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[2];
config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[2];
config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[2];
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json"));
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json"));
return true;
}
@@ -1830,4 +1916,4 @@ namespace ServiceLib.Handler
#endregion Regional Presets
}
}
}

View File

@@ -1,10 +1,12 @@
namespace ServiceLib.Handler
namespace ServiceLib.Handler
{
/// <summary>
/// Core configuration file processing class
/// </summary>
public class CoreConfigHandler
{
private static readonly string _tag = "CoreConfigHandler";
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
{
var config = AppHandler.Instance.Config;
@@ -31,7 +33,7 @@
{
return result;
}
if (Utils.IsNotEmpty(fileName) && result.Data != null)
if (fileName.IsNotEmpty() && result.Data != null)
{
await File.WriteAllTextAsync(fileName, result.Data.ToString());
}
@@ -78,11 +80,11 @@
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
return ret;
return await Task.FromResult(ret);
}
catch (Exception ex)
{
Logging.SaveLog("GenerateClientCustomConfig", ex);
Logging.SaveLog(_tag, ex);
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
@@ -107,6 +109,30 @@
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)
{
var result = new RetResult();
@@ -127,4 +153,4 @@
return result;
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.Text;
namespace ServiceLib.Handler
@@ -13,26 +13,39 @@ namespace ServiceLib.Handler
private Config _config;
private Process? _process;
private Process? _processPre;
private int _linuxSudoPid = -1;
private Action<bool, string>? _updateFunc;
private const string _tag = "CoreHandler";
public async Task Init(Config config, Action<bool, string> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
if (Utils.IsLinux())
//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())
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
foreach (var it in coreInfo)
{
if (it.CoreType == ECoreType.v2rayN)
{
if (Utils.UpgradeAppExists(out var fileName))
if (Utils.UpgradeAppExists(out var upgradeFileName))
{
await Utils.SetLinuxChmod(fileName);
await Utils.SetLinuxChmod(upgradeFileName);
}
continue;
}
@@ -53,55 +66,88 @@ namespace ServiceLib.Handler
{
if (node == null)
{
ShowMsg(false, ResUI.CheckServerSettings);
UpdateFunc(false, ResUI.CheckServerSettings);
return;
}
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
ShowMsg(false, result.Msg);
if (result.Success != true)
{
UpdateFunc(true, result.Msg);
return;
}
else
{
ShowMsg(true, $"{node.GetSummary()}");
await CoreStop();
await CoreStart(node);
//In tun mode, do a delay check and restart the core
//if (_config.tunModeItem.enableTun)
//{
// Observable.Range(1, 1)
// .Delay(TimeSpan.FromSeconds(15))
// .Subscribe(x =>
// {
// {
// if (_process == null || _process.HasExited)
// {
// CoreStart(node);
// ShowMsg(false, "Tun mode restart the core once");
// Logging.SaveLog("Tun mode restart the core once");
// }
// }
// });
//}
UpdateFunc(false, $"{node.GetSummary()}");
UpdateFunc(false, $"{Utils.GetRuntimeInfo()}");
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop();
await Task.Delay(100);
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
{
await Task.Delay(100);
await WindowsUtils.RemoveTunDevice();
}
await CoreStart(node);
await CoreStartPreService(node);
if (_process != null)
{
UpdateFunc(true, $"{node.GetSummary()}");
}
}
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
{
var pid = -1;
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
ShowMsg(false, result.Msg);
if (result.Success)
UpdateFunc(false, result.Msg);
if (result.Success != true)
{
pid = await CoreStartSpeedtest(configPath, coreType);
return -1;
}
return pid;
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
UpdateFunc(false, configPath);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
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)
{
return -1;
}
return proc.Id;
}
public async Task CoreStop()
@@ -110,181 +156,105 @@ namespace ServiceLib.Handler
{
if (_process != null)
{
await KillProcess(_process);
_process.Dispose();
await ProcUtils.ProcessKill(_process, true);
_process = null;
}
if (_processPre != null)
{
await KillProcess(_processPre);
_processPre.Dispose();
await ProcUtils.ProcessKill(_processPre, true);
_processPre = null;
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
public async Task CoreStopPid(int pid)
{
try
{
var _p = Process.GetProcessById(pid);
await KillProcess(_p);
if (_linuxSudoPid > 0)
{
await KillProcessAsLinuxSudo();
}
_linuxSudoPid = -1;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
#region Private
private string CoreFindExe(CoreInfo coreInfo)
{
string fileName = string.Empty;
foreach (var name in coreInfo.CoreExes)
{
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
if (File.Exists(vName))
{
fileName = vName;
break;
}
}
if (Utils.IsNullOrEmpty(fileName))
{
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
Logging.SaveLog(msg);
ShowMsg(false, msg);
}
return fileName;
}
private async Task CoreStart(ProfileItem node)
{
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
//ECoreType coreType;
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
//{
// coreType = ECoreType.sing_box;
//}
//else
//{
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
//}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
_config.RunningCoreType = coreType;
var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
var proc = await RunProcess(node, coreInfo, "", displayLog);
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
if (proc is null)
{
return;
}
_process = proc;
}
//start a pre service
private async Task CoreStartPreService(ProfileItem node)
{
if (_process != null && !_process.HasExited)
{
ProfileItem? itemSocks = null;
var preCoreType = ECoreType.sing_box;
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.TunModeItem.EnableTun)
{
itemSocks = new ProfileItem()
{
CoreType = preCoreType,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Sni = node.Address, //Tun2SocksAddress
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
};
}
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
{
preCoreType = _config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
itemSocks = new ProfileItem()
{
CoreType = preCoreType,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Port = node.PreSocksPort.Value,
};
_config.RunningCoreType = preCoreType;
}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
if (itemSocks != null)
{
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2);
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
if (result.Success)
{
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = await RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true);
if (proc2 is not null)
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
if (proc is null)
{
_processPre = proc2;
return;
}
_processPre = proc;
}
}
}
}
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true);
if (proc is null)
{
return -1;
}
return proc.Id;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
string msg = ex.Message;
ShowMsg(false, msg);
return -1;
}
}
private void ShowMsg(bool notify, string msg)
private void UpdateFunc(bool notify, string msg)
{
_updateFunc?.Invoke(notify, msg);
}
private bool IsNeedSudo(ECoreType eCoreType)
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& (Utils.IsNonWindows())
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
#endregion Private
#region Process
private async Task<Process?> RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog)
private async Task<Process?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
{
var fileName = CoreInfoHandler.Instance.GetCoreExecFile(coreInfo, out var msg);
if (fileName.IsNullOrEmpty())
{
UpdateFunc(false, msg);
return null;
}
try
{
string fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
Process proc = new()
{
StartInfo = new()
{
FileName = fileName,
Arguments = string.Format(coreInfo.Arguments, configPath),
WorkingDirectory = Utils.GetConfigPath(),
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
WorkingDirectory = Utils.GetBinConfigPath(),
UseShellExecute = false,
RedirectStandardOutput = displayLog,
RedirectStandardError = displayLog,
@@ -293,83 +263,147 @@ namespace ServiceLib.Handler
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
}
};
var startUpErrorMessage = new StringBuilder();
var startUpSuccessful = false;
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
}
if (displayLog)
{
proc.OutputDataReceived += (sender, e) =>
{
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
}
if (e.Data.IsNullOrEmpty())
return;
UpdateFunc(false, e.Data + Environment.NewLine);
};
proc.ErrorDataReceived += (sender, e) =>
{
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
if (!startUpSuccessful)
{
startUpErrorMessage.Append(msg);
}
}
if (e.Data.IsNullOrEmpty())
return;
UpdateFunc(false, e.Data + Environment.NewLine);
};
}
proc.Start();
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
if (isNeedSudo)
_linuxSudoPid = proc.Id;
if (displayLog)
{
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
}
if (proc.WaitForExit(1000))
{
proc.CancelErrorRead();
throw new Exception(displayLog ? startUpErrorMessage.ToString() : "启动进程失败并退出 (Failed to start the process and exited)");
}
else
{
startUpSuccessful = true;
}
await Task.Delay(500);
AppHandler.Instance.AddProcess(proc.Handle);
if (proc is null or { HasExited: true })
{
throw new Exception(ResUI.FailedToRunCore);
}
return proc;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
string msg = ex.Message;
ShowMsg(true, msg);
Logging.SaveLog(_tag, ex);
UpdateFunc(mayNeedSudo, ex.Message);
return null;
}
}
private async Task KillProcess(Process? proc)
#endregion Process
#region Linux
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
{
if (proc is null)
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
proc.StartInfo.FileName = shFilePath;
proc.StartInfo.Arguments = "";
proc.StartInfo.WorkingDirectory = "";
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
return;
}
try
{
proc.Kill();
proc.WaitForExit(100);
if (!proc.HasExited)
{
proc.Kill();
proc.WaitForExit(100);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
}
}
#endregion Process
private async Task KillProcessAsLinuxSudo()
{
var cmdLine = $"kill {_linuxSudoPid}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
Process proc = new()
{
StartInfo = new()
{
FileName = shFilePath,
UseShellExecute = false,
CreateNoWindow = true,
StandardInputEncoding = Encoding.UTF8,
RedirectStandardInput = true
}
};
proc.Start();
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
try
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
catch (Exception)
{
// ignored
}
}
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await proc.WaitForExitAsync(timeout.Token);
await Task.Delay(3000);
}
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
{
//Shell scripts
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
if (AppHandler.Instance.IsAdministrator)
{
sb.AppendLine($"{cmdLine}");
}
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
{
sb.AppendLine($"pkexec {cmdLine}");
}
else
{
sb.AppendLine($"sudo -S {cmdLine}");
}
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
Logging.SaveLog(shFilePath);
return shFilePath;
}
#endregion Linux
}
}
}

View File

@@ -1,5 +1,3 @@
using System.Runtime.Intrinsics.X86;
namespace ServiceLib.Handler
{
public sealed class CoreInfoHandler
@@ -31,143 +29,190 @@ namespace ServiceLib.Handler
return _coreInfo ?? [];
}
public string GetCoreExecFile(CoreInfo? coreInfo, out string msg)
{
var fileName = string.Empty;
msg = string.Empty;
foreach (var name in coreInfo?.CoreExes)
{
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
if (File.Exists(vName))
{
fileName = vName;
break;
}
}
if (fileName.IsNullOrEmpty())
{
msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo?.CoreType.ToString()), coreInfo?.CoreExes?.LastOrDefault(), coreInfo?.Url);
Logging.SaveLog(msg);
}
return fileName;
}
private void InitCoreInfo()
{
_coreInfo = [];
var urlN = GetCoreUrl(ECoreType.v2rayN);
var urlXray = GetCoreUrl(ECoreType.Xray);
var urlMihomo = GetCoreUrl(ECoreType.mihomo);
var urlSingbox = GetCoreUrl(ECoreType.sing_box);
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.v2rayN,
Url = Global.NUrl,
ReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.NUrl + "/download/{0}/v2rayN-windows-64.zip",
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
});
_coreInfo =
[
new CoreInfo
{
CoreType = ECoreType.v2rayN,
Url = GetCoreUrl(ECoreType.v2rayN),
ReleaseApiUrl = urlN.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = urlN + "/download/{0}/v2rayN-windows-64.zip",
DownloadUrlWinArm64 = urlN + "/download/{0}/v2rayN-windows-arm64.zip",
DownloadUrlLinux64 = urlN + "/download/{0}/v2rayN-linux-64.zip",
DownloadUrlLinuxArm64 = urlN + "/download/{0}/v2rayN-linux-arm64.zip",
DownloadUrlOSX64 = urlN + "/download/{0}/v2rayN-macos-64.zip",
DownloadUrlOSXArm64 = urlN + "/download/{0}/v2rayN-macos-arm64.zip",
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.v2fly,
CoreExes = new List<string> { "wv2ray", "v2ray" },
Arguments = "",
Url = Global.V2flyCoreUrl,
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
Match = "V2Ray",
VersionArg = "-version",
RedirectInfo = true,
});
new CoreInfo
{
CoreType = ECoreType.v2fly,
CoreExes = ["v2ray"],
Arguments = "{0}",
Url = GetCoreUrl(ECoreType.v2fly),
Match = "V2Ray",
VersionArg = "-version",
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.v2fly_v5,
CoreExes = new List<string> { "v2ray" },
Arguments = "run -c config.json -format jsonv5",
Url = Global.V2flyCoreUrl,
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
Match = "V2Ray",
VersionArg = "version",
RedirectInfo = true,
});
new CoreInfo
{
CoreType = ECoreType.v2fly_v5,
CoreExes = ["v2ray"],
Arguments = "run -c {0} -format jsonv5",
Url = GetCoreUrl(ECoreType.v2fly_v5),
Match = "V2Ray",
VersionArg = "version",
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.Xray,
CoreExes = new List<string> { "xray", "wxray" },
Arguments = "run {0}",
Url = Global.XrayCoreUrl,
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
Match = "Xray",
VersionArg = "-version",
RedirectInfo = true,
});
new CoreInfo
{
CoreType = ECoreType.Xray,
CoreExes = ["xray"],
Arguments = "run -c {0}",
Url = GetCoreUrl(ECoreType.Xray),
ReleaseApiUrl = urlXray.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = urlXray + "/download/{0}/Xray-windows-64.zip",
DownloadUrlWinArm64 = urlXray + "/download/{0}/Xray-windows-arm64-v8a.zip",
DownloadUrlLinux64 = urlXray + "/download/{0}/Xray-linux-64.zip",
DownloadUrlLinuxArm64 = urlXray + "/download/{0}/Xray-linux-arm64-v8a.zip",
DownloadUrlOSX64 = urlXray + "/download/{0}/Xray-macos-64.zip",
DownloadUrlOSXArm64 = urlXray + "/download/{0}/Xray-macos-arm64-v8a.zip",
Match = "Xray",
VersionArg = "-version",
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.mihomo,
CoreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" },
Arguments = "-f config.json" + PortableMode(),
Url = Global.MihomoCoreUrl,
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
Match = "Mihomo",
VersionArg = "-v",
RedirectInfo = true,
});
new CoreInfo
{
CoreType = ECoreType.mihomo,
CoreExes = ["mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "clash", "mihomo"],
Arguments = "-f {0}" + PortableMode(),
Url = GetCoreUrl(ECoreType.mihomo),
ReleaseApiUrl = urlMihomo.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = urlMihomo + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
DownloadUrlWinArm64 = urlMihomo + "/download/{0}/mihomo-windows-arm64-{0}.zip",
DownloadUrlLinux64 = urlMihomo + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
DownloadUrlLinuxArm64 = urlMihomo + "/download/{0}/mihomo-linux-arm64-{0}.gz",
DownloadUrlOSX64 = urlMihomo + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz",
DownloadUrlOSXArm64 = urlMihomo + "/download/{0}/mihomo-darwin-arm64-{0}.gz",
Match = "Mihomo",
VersionArg = "-v",
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.hysteria,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
Arguments = "",
Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
RedirectInfo = true,
});
new CoreInfo
{
CoreType = ECoreType.hysteria,
CoreExes = ["hysteria"],
Arguments = "",
Url = GetCoreUrl(ECoreType.hysteria),
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.naiveproxy,
CoreExes = new List<string> { "naiveproxy", "naive" },
Arguments = "config.json",
Url = Global.NaiveproxyCoreUrl,
RedirectInfo = false,
});
new CoreInfo
{
CoreType = ECoreType.naiveproxy,
CoreExes = [ "naive", "naiveproxy"],
Arguments = "{0}",
Url = GetCoreUrl(ECoreType.naiveproxy),
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.tuic,
CoreExes = new List<string> { "tuic-client", "tuic" },
Arguments = "-c config.json",
Url = Global.TuicCoreUrl,
RedirectInfo = true,
});
new CoreInfo
{
CoreType = ECoreType.tuic,
CoreExes = ["tuic-client", "tuic"],
Arguments = "-c {0}",
Url = GetCoreUrl(ECoreType.tuic),
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.sing_box,
CoreExes = new List<string> { "sing-box-client", "sing-box" },
Arguments = "run {0} --disable-color",
Url = Global.SingboxCoreUrl,
RedirectInfo = true,
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
Match = "sing-box",
VersionArg = "version",
});
new CoreInfo
{
CoreType = ECoreType.sing_box,
CoreExes = ["sing-box-client", "sing-box"],
Arguments = "run -c {0} --disable-color",
Url = GetCoreUrl(ECoreType.sing_box),
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.juicity,
CoreExes = new List<string> { "juicity-client", "juicity" },
Arguments = "run -c config.json",
Url = Global.JuicityCoreUrl
});
ReleaseApiUrl = urlSingbox.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = urlSingbox + "/download/{0}/sing-box-{1}-windows-amd64.zip",
DownloadUrlWinArm64 = urlSingbox + "/download/{0}/sing-box-{1}-windows-arm64.zip",
DownloadUrlLinux64 = urlSingbox + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
DownloadUrlLinuxArm64 = urlSingbox + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
DownloadUrlOSX64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz",
DownloadUrlOSXArm64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz",
Match = "sing-box",
VersionArg = "version",
},
_coreInfo.Add(new CoreInfo
{
CoreType = ECoreType.hysteria2,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" },
Arguments = "",
Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
RedirectInfo = true,
});
new CoreInfo
{
CoreType = ECoreType.juicity,
CoreExes = ["juicity-client", "juicity"],
Arguments = "run -c {0}",
Url = GetCoreUrl(ECoreType.juicity)
},
new CoreInfo
{
CoreType = ECoreType.hysteria2,
CoreExes = ["hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria"],
Arguments = "",
Url = GetCoreUrl(ECoreType.hysteria2),
},
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("")}\"";
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
{
@@ -16,12 +16,12 @@ namespace ServiceLib.Handler.Fmt
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
{
if (Utils.IsNotEmpty(item.Flow))
if (item.Flow.IsNotEmpty())
{
dicQuery.Add("flow", item.Flow);
}
if (Utils.IsNotEmpty(item.StreamSecurity))
if (item.StreamSecurity.IsNotEmpty())
{
dicQuery.Add("security", item.StreamSecurity);
}
@@ -32,27 +32,27 @@ namespace ServiceLib.Handler.Fmt
dicQuery.Add("security", securityDef);
}
}
if (Utils.IsNotEmpty(item.Sni))
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (Utils.IsNotEmpty(item.Alpn))
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
if (Utils.IsNotEmpty(item.Fingerprint))
if (item.Fingerprint.IsNotEmpty())
{
dicQuery.Add("fp", Utils.UrlEncode(item.Fingerprint));
}
if (Utils.IsNotEmpty(item.PublicKey))
if (item.PublicKey.IsNotEmpty())
{
dicQuery.Add("pbk", Utils.UrlEncode(item.PublicKey));
}
if (Utils.IsNotEmpty(item.ShortId))
if (item.ShortId.IsNotEmpty())
{
dicQuery.Add("sid", Utils.UrlEncode(item.ShortId));
}
if (Utils.IsNotEmpty(item.SpiderX))
if (item.SpiderX.IsNotEmpty())
{
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
}
@@ -61,21 +61,21 @@ namespace ServiceLib.Handler.Fmt
dicQuery.Add("allowInsecure", "1");
}
dicQuery.Add("type", Utils.IsNotEmpty(item.Network) ? item.Network : nameof(ETransport.tcp));
dicQuery.Add("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp));
switch (item.Network)
{
case nameof(ETransport.tcp):
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
if (Utils.IsNotEmpty(item.RequestHost))
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
break;
case nameof(ETransport.kcp):
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
if (Utils.IsNotEmpty(item.Path))
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
if (item.Path.IsNotEmpty())
{
dicQuery.Add("seed", Utils.UrlEncode(item.Path));
}
@@ -83,38 +83,56 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
if (Utils.IsNotEmpty(item.RequestHost))
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (Utils.IsNotEmpty(item.Path))
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
break;
case nameof(ETransport.xhttp):
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
if (item.HeaderType.IsNotEmpty() && Global.XhttpMode.Contains(item.HeaderType))
{
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
}
if (item.Extra.IsNotEmpty())
{
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
}
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http);
if (Utils.IsNotEmpty(item.RequestHost))
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (Utils.IsNotEmpty(item.Path))
if (item.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
break;
case nameof(ETransport.quic):
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.RequestHost));
dicQuery.Add("key", Utils.UrlEncode(item.Path));
break;
case nameof(ETransport.grpc):
if (Utils.IsNotEmpty(item.Path))
if (item.Path.IsNotEmpty())
{
dicQuery.Add("authority", Utils.UrlEncode(item.RequestHost));
dicQuery.Add("serviceName", Utils.UrlEncode(item.Path));
@@ -156,11 +174,17 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
break;
case nameof(ETransport.xhttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? "");
item.Extra = Utils.UrlDecode(query["extra"] ?? "");
break;
case nameof(ETransport.http):
case nameof(ETransport.h2):
item.Network = nameof(ETransport.h2);
@@ -190,7 +214,10 @@ namespace ServiceLib.Handler.Fmt
{
foreach (var item in s)
{
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
if (str.Contains(item, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
@@ -212,4 +239,4 @@ namespace ServiceLib.Handler.Fmt
return $"{Global.ProtocolShares[eConfigType]}{url}{query}{remark}";
}
}
}
}

View File

@@ -2,6 +2,8 @@
{
public class FmtHandler
{
private static readonly string _tag = "FmtHandler";
public static string? GetShareUri(ProfileItem item)
{
try
@@ -23,7 +25,7 @@
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
return "";
}
}
@@ -35,7 +37,7 @@
try
{
string str = config.TrimEx();
if (Utils.IsNullOrEmpty(str))
if (str.IsNullOrEmpty())
{
msg = ResUI.FailedReadConfiguration;
return null;
@@ -81,7 +83,7 @@
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
msg = ResUI.Incorrectconfiguration;
return null;
}

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
public class Hysteria2Fmt : BaseFmt
{
@@ -11,7 +11,8 @@
};
var url = Utils.TryUri(str);
if (url == null) return null;
if (url == null)
return null;
item.Address = url.IdnHost;
item.Port = url.Port;
@@ -23,34 +24,41 @@
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
if (item == null)
return null;
string url = string.Empty;
string remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks))
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (Utils.IsNotEmpty(item.Sni))
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (Utils.IsNotEmpty(item.Alpn))
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
if (Utils.IsNotEmpty(item.Path))
if (item.Path.IsNotEmpty())
{
dicQuery.Add("obfs", "salamander");
dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
}
dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0");
if (item.Ports.IsNotEmpty())
{
dicQuery.Add("mport", Utils.UrlEncode(item.Ports.Replace(':', '-')));
}
return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark);
}
@@ -91,4 +99,4 @@
return null;
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
namespace ServiceLib.Handler.Fmt
{
@@ -26,11 +26,12 @@ namespace ServiceLib.Handler.Fmt
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks))
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
@@ -52,12 +53,14 @@ namespace ServiceLib.Handler.Fmt
{
var match = UrlFinder.Match(result);
if (!match.Success)
{
return null;
}
ProfileItem item = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (Utils.IsNotEmpty(tag))
if (tag.IsNotEmpty())
{
item.Remarks = Utils.UrlDecode(tag);
}
@@ -71,18 +74,23 @@ namespace ServiceLib.Handler.Fmt
return null;
}
if (!details.Success)
{
return null;
}
item.Security = details.Groups["method"].Value;
item.Id = details.Groups["password"].Value;
item.Address = details.Groups["hostname"].Value;
item.Port = Utils.ToInt(details.Groups["port"].Value);
item.Port = details.Groups["port"].Value.ToInt();
return item;
}
private static ProfileItem? ResolveSip002(string result)
{
var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null) return null;
if (parsedUrl == null)
{
return null;
}
ProfileItem item = new()
{
@@ -94,25 +102,25 @@ namespace ServiceLib.Handler.Fmt
//2022-blake3
if (rawUserInfo.Contains(':'))
{
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.Security = userInfoParts[0];
item.Id = Utils.UrlDecode(userInfoParts[1]);
item.Security = userInfoParts.First();
item.Id = Utils.UrlDecode(userInfoParts.Last());
}
else
{
// parse base64 UserInfo
string userInfo = Utils.Base64Decode(rawUserInfo);
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
var userInfo = Utils.Base64Decode(rawUserInfo);
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length != 2)
{
return null;
}
item.Security = userInfoParts[0];
item.Id = userInfoParts[1];
item.Security = userInfoParts.First();
item.Id = userInfoParts.Last();
}
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
@@ -120,7 +128,7 @@ namespace ServiceLib.Handler.Fmt
{
//obfs-host exists
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
if (queryParameters["plugin"].Contains("obfs=http") && Utils.IsNotEmpty(obfsHost))
if (queryParameters["plugin"].Contains("obfs=http") && obfsHost.IsNotEmpty())
{
obfsHost = obfsHost?.Replace("obfs-host=", "");
item.Network = Global.DefaultNetwork;
@@ -160,7 +168,7 @@ namespace ServiceLib.Handler.Fmt
Security = it.method,
Id = it.password,
Address = it.server,
Port = Utils.ToInt(it.server_port)
Port = it.server_port.ToInt()
};
lst.Add(ssItem);
}
@@ -169,4 +177,4 @@ namespace ServiceLib.Handler.Fmt
return null;
}
}
}
}

View File

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

View File

@@ -1,13 +1,12 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
public class SocksFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item;
item = ResolveSocksNew(str) ?? ResolveSocks(str);
var item = ResolveSocksNew(str) ?? ResolveSocks(str);
if (item == null)
{
return null;
@@ -24,20 +23,15 @@
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks))
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
//url = string.Format("{0}:{1}@{2}:{3}",
// item.security,
// item.id,
// item.address,
// item.port);
//url = Utile.Base64Encode(url);
//new
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
@@ -51,7 +45,7 @@
};
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
//remark
int indexRemark = result.IndexOf("#");
var indexRemark = result.IndexOf("#");
if (indexRemark > 0)
{
try
@@ -62,7 +56,7 @@
result = result[..indexRemark];
}
//part decode
int indexS = result.IndexOf("@");
var indexS = result.IndexOf("@");
if (indexS > 0)
{
}
@@ -71,21 +65,20 @@
result = Utils.Base64Decode(result);
}
string[] arr1 = result.Split('@');
var arr1 = result.Split('@');
if (arr1.Length != 2)
{
return null;
}
string[] arr21 = arr1[0].Split(':');
//string[] arr22 = arr1[1].Split(':');
int indexPort = arr1[1].LastIndexOf(":");
var arr21 = arr1.First().Split(':');
var indexPort = arr1.Last().LastIndexOf(":");
if (arr21.Length != 2 || indexPort < 0)
{
return null;
}
item.Address = arr1[1][..indexPort];
item.Port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
item.Security = arr21[0];
item.Port = arr1[1][(indexPort + 1)..].ToInt();
item.Security = arr21.First();
item.Id = arr21[1];
return item;
@@ -94,7 +87,10 @@
private static ProfileItem? ResolveSocksNew(string result)
{
var parsedUrl = Utils.TryUri(result);
if (parsedUrl == null) return null;
if (parsedUrl == null)
{
return null;
}
ProfileItem item = new()
{
@@ -106,14 +102,14 @@
// parse base64 UserInfo
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
var userInfo = Utils.Base64Decode(rawUserInfo);
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
var userInfoParts = userInfo.Split([':'], 2);
if (userInfoParts.Length == 2)
{
item.Security = userInfoParts[0];
item.Security = userInfoParts.First();
item.Id = userInfoParts[1];
}
return item;
}
}
}
}

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
public class TrojanFmt : BaseFmt
{
@@ -12,7 +12,10 @@
};
var url = Utils.TryUri(str);
if (url == null) return null;
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
@@ -20,25 +23,26 @@
item.Id = Utils.UrlDecode(url.UserInfo);
var query = Utils.ParseQueryString(url.Query);
ResolveStdTransport(query, ref item);
_ = ResolveStdTransport(query, ref item);
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
string remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks))
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
GetStdTransport(item, null, ref dicQuery);
_ = GetStdTransport(item, null, ref dicQuery);
return ToUri(EConfigType.Trojan, item.Address, item.Port, item.Id, dicQuery, remark);
}
}
}
}

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
public class TuicFmt : BaseFmt
{
@@ -12,7 +12,10 @@
};
var url = Utils.TryUri(str);
if (url == null) return null;
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
@@ -21,8 +24,8 @@
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2)
{
item.Id = userInfoParts[0];
item.Security = userInfoParts[1];
item.Id = userInfoParts.First();
item.Security = userInfoParts.Last();
}
var query = Utils.ParseQueryString(url.Query);
@@ -34,20 +37,22 @@
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
if (item == null)
{
return null;
}
string remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks))
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (Utils.IsNotEmpty(item.Sni))
if (item.Sni.IsNotEmpty())
{
dicQuery.Add("sni", item.Sni);
}
if (Utils.IsNotEmpty(item.Alpn))
if (item.Alpn.IsNotEmpty())
{
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
}
@@ -56,4 +61,4 @@
return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Id}:{item.Security}", dicQuery, remark);
}
}
}
}

View File

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

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
public class VLESSFmt : BaseFmt
{
@@ -13,7 +13,10 @@
};
var url = Utils.TryUri(str);
if (url == null) return null;
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
@@ -23,23 +26,25 @@
var query = Utils.ParseQueryString(url.Query);
item.Security = query["encryption"] ?? Global.None;
item.StreamSecurity = query["security"] ?? "";
ResolveStdTransport(query, ref item);
_ = ResolveStdTransport(query, ref item);
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
if (item == null)
{
return null;
}
string remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks))
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (Utils.IsNotEmpty(item.Security))
if (item.Security.IsNotEmpty())
{
dicQuery.Add("encryption", item.Security);
}
@@ -47,9 +52,9 @@
{
dicQuery.Add("encryption", Global.None);
}
GetStdTransport(item, Global.None, ref dicQuery);
_ = GetStdTransport(item, Global.None, ref dicQuery);
return ToUri(EConfigType.VLESS, item.Address, item.Port, item.Id, dicQuery, remark);
}
}
}
}

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
public class VmessFmt : BaseFmt
{
@@ -19,10 +19,11 @@
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
VmessQRCode vmessQRCode = new()
if (item == null)
{
return null;
}
var vmessQRCode = new VmessQRCode
{
v = item.ConfigVersion,
ps = item.Remarks.TrimEx(),
@@ -41,7 +42,7 @@
fp = item.Fingerprint
};
url = JsonUtils.Serialize(vmessQRCode);
var url = JsonUtils.Serialize(vmessQRCode);
url = Utils.Base64Encode(url);
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
@@ -59,7 +60,7 @@
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
result = Utils.Base64Decode(result);
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
var vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
if (vmessQRCode == null)
{
msg = ResUI.FailedConversionConfiguration;
@@ -77,12 +78,12 @@
item.AlterId = vmessQRCode.aid;
item.Security = Utils.ToString(vmessQRCode.scy);
item.Security = Utils.IsNotEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
if (Utils.IsNotEmpty(vmessQRCode.net))
item.Security = vmessQRCode.scy.IsNotEmpty() ? vmessQRCode.scy : Global.DefaultSecurity;
if (vmessQRCode.net.IsNotEmpty())
{
item.Network = vmessQRCode.net;
}
if (Utils.IsNotEmpty(vmessQRCode.type))
if (vmessQRCode.type.IsNotEmpty())
{
item.HeaderType = vmessQRCode.type;
}
@@ -99,14 +100,17 @@
public static ProfileItem? ResolveStdVmess(string str)
{
ProfileItem item = new()
var item = new ProfileItem
{
ConfigType = EConfigType.VMess,
Security = "auto"
};
var url = Utils.TryUri(str);
if (url == null) return null;
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
@@ -119,4 +123,4 @@
return item;
}
}
}
}

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler.Fmt
namespace ServiceLib.Handler.Fmt
{
public class WireguardFmt : BaseFmt
{
@@ -12,7 +12,10 @@
};
var url = Utils.TryUri(str);
if (url == null) return null;
if (url == null)
{
return null;
}
item.Address = url.IdnHost;
item.Port = url.Port;
@@ -31,33 +34,35 @@
public static string? ToUri(ProfileItem? item)
{
if (item == null) return null;
string url = string.Empty;
if (item == null)
{
return null;
}
string remark = string.Empty;
if (Utils.IsNotEmpty(item.Remarks))
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var dicQuery = new Dictionary<string, string>();
if (Utils.IsNotEmpty(item.PublicKey))
if (item.PublicKey.IsNotEmpty())
{
dicQuery.Add("publickey", Utils.UrlEncode(item.PublicKey));
}
if (Utils.IsNotEmpty(item.Path))
if (item.Path.IsNotEmpty())
{
dicQuery.Add("reserved", Utils.UrlEncode(item.Path));
}
if (Utils.IsNotEmpty(item.RequestHost))
if (item.RequestHost.IsNotEmpty())
{
dicQuery.Add("address", Utils.UrlEncode(item.RequestHost));
}
if (Utils.IsNotEmpty(item.ShortId))
if (item.ShortId.IsNotEmpty())
{
dicQuery.Add("mtu", Utils.UrlEncode(item.ShortId));
}
return ToUri(EConfigType.WireGuard, item.Address, item.Port, item.Id, dicQuery, remark);
}
}
}
}

View File

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

View File

@@ -1,4 +1,4 @@
using System.Collections.Concurrent;
using System.Collections.Concurrent;
//using System.Reactive.Linq;
@@ -8,8 +8,9 @@ namespace ServiceLib.Handler
{
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
private Queue<string> _queIndexIds = new();
private readonly Queue<string> _queIndexIds = new();
public static ProfileExHandler Instance => _instance.Value;
private static readonly string _tag = "ProfileExHandler";
public ProfileExHandler()
{
@@ -19,19 +20,11 @@ namespace ServiceLib.Handler
public async Task Init()
{
await InitData();
Task.Run(async () =>
{
while (true)
{
await Task.Delay(1000 * 600);
await SaveQueueIndexIds();
}
});
}
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()
{
return _lstProfileEx;
return await Task.FromResult(_lstProfileEx);
}
private async Task InitData()
@@ -43,7 +36,7 @@ namespace ServiceLib.Handler
private void IndexIdEnqueue(string indexId)
{
if (Utils.IsNotEmpty(indexId) && !_queIndexIds.Contains(indexId))
if (indexId.IsNotEmpty() && !_queIndexIds.Contains(indexId))
{
_queIndexIds.Enqueue(indexId);
}
@@ -58,7 +51,7 @@ namespace ServiceLib.Handler
List<ProfileExItem> lstInserts = [];
List<ProfileExItem> lstUpdates = [];
for (int i = 0; i < cnt; i++)
for (var i = 0; i < cnt; i++)
{
var id = _queIndexIds.Dequeue();
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
@@ -77,32 +70,44 @@ namespace ServiceLib.Handler
lstInserts.Add(itemNew);
}
}
try
{
if (lstInserts.Count() > 0)
if (lstInserts.Count > 0)
{
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
}
if (lstUpdates.Count() > 0)
if (lstUpdates.Count > 0)
{
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
}
}
catch (Exception ex)
{
Logging.SaveLog("ProfileExHandler", ex);
Logging.SaveLog(_tag, ex);
}
}
}
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx)
private ProfileExItem AddProfileEx(string indexId)
{
profileEx = new()
var profileEx = new ProfileExItem()
{
IndexId = indexId,
Delay = 0,
Speed = 0,
Sort = 0
Sort = 0,
Message = string.Empty
};
_lstProfileEx.Add(profileEx);
IndexIdEnqueue(indexId);
return profileEx;
}
private ProfileExItem GetProfileExItem(string? indexId)
{
return _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId) ?? AddProfileEx(indexId);
}
public async Task ClearAll()
@@ -119,43 +124,38 @@ namespace ServiceLib.Handler
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
public void SetTestDelay(string indexId, string delayVal)
public void SetTestDelay(string indexId, int delay)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
var profileEx = GetProfileExItem(indexId);
int.TryParse(delayVal, out int delay);
profileEx.Delay = delay;
IndexIdEnqueue(indexId);
}
public void SetTestSpeed(string indexId, string speedVal)
public void SetTestSpeed(string indexId, decimal speed)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
var profileEx = GetProfileExItem(indexId);
decimal.TryParse(speedVal, out decimal speed);
profileEx.Speed = speed;
IndexIdEnqueue(indexId);
}
public void SetTestMessage(string indexId, string message)
{
var profileEx = GetProfileExItem(indexId);
profileEx.Message = message;
IndexIdEnqueue(indexId);
}
public void SetSort(string indexId, int sort)
{
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
if (profileEx == null)
{
AddProfileEx(indexId, ref profileEx);
}
var profileEx = GetProfileExItem(indexId);
profileEx.Sort = sort;
IndexIdEnqueue(indexId);
}
@@ -179,4 +179,4 @@ namespace ServiceLib.Handler
return _lstProfileEx.Max(t => t == null ? 0 : t.Sort);
}
}
}
}

View File

@@ -9,36 +9,35 @@
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc;
private StatisticsV2rayService? _statisticsV2Ray;
private StatisticsSingboxService? _statisticsSingbox;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox;
private static readonly string _tag = "StatisticsHandler";
public List<ServerStatItem> ServerStat => _lstServerStat;
public async Task Init(Config config, Action<ServerSpeedItem> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
if (!config.GuiItem.EnableStatistics)
if (config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
{
return;
await InitData();
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
}
await InitData();
_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
}
public void Close()
{
try
{
_statisticsV2Ray?.Close();
_statisticsXray?.Close();
_statisticsSingbox?.Close();
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
@@ -60,10 +59,34 @@
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
Logging.SaveLog(_tag, ex);
}
}
public async Task CloneServerStatItem(string indexId, string toIndexId)
{
if (_lstServerStat == null)
{
return;
}
if (indexId == toIndexId)
{
return;
}
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
if (stat == null)
{
return;
}
var toStat = JsonUtils.DeepCopy(stat);
toStat.IndexId = toIndexId;
await SQLiteHelper.Instance.ReplaceAsync(toStat);
_lstServerStat.Add(toStat);
}
private async Task InitData()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");
@@ -76,7 +99,7 @@
private void UpdateServerStatHandler(ServerSpeedItem server)
{
UpdateServerStat(server);
_ = UpdateServerStat(server);
}
private async Task UpdateServerStat(ServerSpeedItem server)

View File

@@ -1,152 +1,33 @@
namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy
{
public class ProxySettingLinux
{
public static async Task SetProxy(string host, int port)
{
var lstCmd = GetSetCmds(host, port);
private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh";
await ExecCmd(lstCmd);
public static async Task SetProxy(string host, int port, string exceptions)
{
List<string> args = ["manual", host, port.ToString(), exceptions];
await ExecCmd(args);
}
public static async Task UnsetProxy()
{
var lstCmd = GetUnsetCmds();
await ExecCmd(lstCmd);
List<string> args = ["none"];
await ExecCmd(args);
}
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)
{
continue;
}
await Task.Delay(10);
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
}
}
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
await File.AppendAllTextAsync(fileName, contents);
private static List<CmdItem> GetSetCmds(string host, int port)
{
var isKde = IsKde(out var configDir);
List<string> lstType = ["", "http", "https", "socks", "ftp"];
List<CmdItem> lstCmd = [];
if (isKde)
{
foreach (var type in lstType)
{
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
}
}
else
{
foreach (var type in lstType)
{
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
}
}
return lstCmd;
}
private static List<CmdItem> GetUnsetCmds()
{
var isKde = IsKde(out var configDir);
List<CmdItem> lstCmd = [];
if (isKde)
{
lstCmd.Add(new CmdItem()
{
Cmd = "kwriteconfig5",
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
});
}
else
{
lstCmd.Add(new CmdItem()
{
Cmd = "gsettings",
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
});
await Utils.SetLinuxChmod(fileName);
}
return lstCmd;
}
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
{
List<CmdItem> lstCmd = [];
if (type.IsNullOrEmpty())
{
lstCmd.Add(new()
{
Cmd = "kwriteconfig5",
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
});
}
else
{
var type2 = type.Equals("https") ? "http" : type;
lstCmd.Add(new CmdItem()
{
Cmd = "kwriteconfig5",
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
{
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 isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase);
if (isKde)
{
var homeDir = Environment.GetEnvironmentVariable("HOME");
if (homeDir != null)
{
configDir = Path.Combine(homeDir, ".config");
}
}
return isKde;
await Utils.GetCliWrapOutput(fileName, args);
}
}
}
}

View File

@@ -1,13 +1,38 @@
namespace ServiceLib.Handler.SysProxy
namespace ServiceLib.Handler.SysProxy
{
public class ProxySettingOSX
{
public static async Task SetProxy(string host, int port)
private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh";
public static async Task SetProxy(string host, int port, string exceptions)
{
List<string> args = ["set", host, port.ToString()];
if (exceptions.IsNotEmpty())
{
args.AddRange(exceptions.Split(','));
}
await ExecCmd(args);
}
public static async Task UnsetProxy()
{
List<string> args = ["clear"];
await ExecCmd(args);
}
private static async Task ExecCmd(List<string> args)
{
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
if (!File.Exists(fileName))
{
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
await Utils.GetCliWrapOutput(fileName, args);
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using static ServiceLib.Handler.SysProxy.ProxySettingWindows.InternetConnectionOption;
namespace ServiceLib.Handler.SysProxy
@@ -60,7 +60,7 @@ namespace ServiceLib.Handler.SysProxy
try
{
// set proxy for LAN
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
var result = SetConnectionProxy(null, strProxy, exceptions, type);
// set proxy for dial up connections
var connections = EnumerateRasEntries();
foreach (var connection in connections)
@@ -69,30 +69,29 @@ namespace ServiceLib.Handler.SysProxy
}
return result;
}
catch (Exception ex)
catch
{
SetProxyFallback(strProxy, exceptions, type);
//Logging.SaveLog(ex.Message, ex);
_ = SetProxyFallback(strProxy, exceptions, type);
return false;
}
}
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
{
InternetPerConnOptionList list = new();
var list = new InternetPerConnOptionList();
int optionCount = 1;
var optionCount = 1;
if (type == 1) // No proxy
{
optionCount = 1;
}
else if (type is 2 or 4) // named proxy or autoproxy script URL
{
optionCount = string.IsNullOrEmpty(exceptions) ? 2 : 3;
optionCount = exceptions.IsNullOrEmpty() ? 2 : 3;
}
int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
PerConnOption m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
var m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
var m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
if (type == 2) // named proxy
{
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
@@ -104,11 +103,9 @@ namespace ServiceLib.Handler.SysProxy
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
}
//int optionCount = Utile.IsNullOrEmpty(strProxy) ? 1 : (Utile.IsNullOrEmpty(exceptions) ? 2 : 3);
InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
var options = new InternetConnectionOption[optionCount];
// USE a proxy server ...
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
//options[0].m_Value.m_Int = (int)((optionCount < 2) ? PerConnFlags.PROXY_TYPE_DIRECT : (PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY));
options[0].m_Value.m_Int = m_Int;
// use THIS proxy server
if (optionCount > 1)
@@ -136,20 +133,20 @@ namespace ServiceLib.Handler.SysProxy
list.dwOptionCount = options.Length;
list.dwOptionError = 0;
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
var optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
// make a pointer out of all that ...
nint optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
var optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
// copy the array over into that spot in memory ...
for (int i = 0; i < options.Length; ++i)
for (var i = 0; i < options.Length; ++i)
{
if (Environment.Is64BitOperatingSystem)
{
nint opt = new(optionsPtr.ToInt64() + i * optSize);
var opt = new nint(optionsPtr.ToInt64() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
else
{
nint opt = new(optionsPtr.ToInt32() + i * optSize);
var opt = new nint(optionsPtr.ToInt32() + (i * optSize));
Marshal.StructureToPtr(options[i], opt, false);
}
}
@@ -157,14 +154,14 @@ namespace ServiceLib.Handler.SysProxy
list.options = optionsPtr;
// and then make a pointer out of the whole list
nint ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
var ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
Marshal.StructureToPtr(list, ipcoListPtr, false);
// and finally, call the API method!
bool isSuccess = NativeMethods.InternetSetOption(nint.Zero,
var isSuccess = NativeMethods.InternetSetOption(nint.Zero,
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
ipcoListPtr, list.dwSize);
int returnvalue = 0; // ERROR_SUCCESS
var returnvalue = 0; // ERROR_SUCCESS
if (!isSuccess)
{ // get the error codes, they might be helpful
returnvalue = Marshal.GetLastPInvokeError();
@@ -172,12 +169,15 @@ namespace ServiceLib.Handler.SysProxy
else
{
// Notify the system that the registry settings have been changed and cause them to be refreshed
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
}
// 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)
{
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
@@ -204,18 +204,18 @@ namespace ServiceLib.Handler.SysProxy
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
private static IEnumerable<string> EnumerateRasEntries()
{
int entries = 0;
var entries = 0;
// attempt to query with 1 entry buffer
RASENTRYNAME[] rasEntryNames = new RASENTRYNAME[1];
int bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
var rasEntryNames = new RASENTRYNAME[1];
var bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
uint result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
var result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
// increase buffer if the buffer is not large enough
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
{
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
for (int i = 0; i < rasEntryNames.Length; i++)
for (var i = 0; i < rasEntryNames.Length; i++)
{
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
}
@@ -225,7 +225,7 @@ namespace ServiceLib.Handler.SysProxy
if (result == 0)
{
var entryNames = new List<string>();
for (int i = 0; i < entries; i++)
for (var i = 0; i < entries; i++)
{
entryNames.Add(rasEntryNames[i].szEntryName);
}
@@ -247,7 +247,7 @@ namespace ServiceLib.Handler.SysProxy
//[MarshalAs(UnmanagedType.)]
public nint options;
};
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption
@@ -357,4 +357,4 @@ namespace ServiceLib.Handler.SysProxy
);
}
}
}
}

View File

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

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler
namespace ServiceLib.Handler
{
public class TaskHandler
{
@@ -7,66 +7,92 @@
public void RegUpdateTask(Config config, Action<bool, string> updateFunc)
{
Task.Run(() => UpdateTaskRunSubscription(config, updateFunc));
Task.Run(() => UpdateTaskRunGeo(config, updateFunc));
Task.Run(() => ScheduledTasks(config, updateFunc));
}
private async Task ScheduledTasks(Config config, Action<bool, string> updateFunc)
{
Logging.SaveLog("Setup Scheduled Tasks");
var numOfExecuted = 1;
while (true)
{
//1 minute
await Task.Delay(1000 * 60);
//Execute once 1 minute
await UpdateTaskRunSubscription(config, updateFunc);
//Execute once 20 minute
if (numOfExecuted % 20 == 0)
{
//Logging.SaveLog("Execute save config");
await ConfigHandler.SaveConfig(config);
await ProfileExHandler.Instance.SaveTo();
}
//Execute once 1 hour
if (numOfExecuted % 60 == 0)
{
//Logging.SaveLog("Execute delete expired files");
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
//Check once 1 hour
await UpdateTaskRunGeo(config, numOfExecuted / 60, updateFunc);
}
numOfExecuted++;
}
}
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc)
{
await Task.Delay(60000);
Logging.SaveLog("UpdateTaskRunSubscription");
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = (await AppHandler.Instance.SubItems())?
.Where(t => t.AutoUpdateInterval > 0)
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
.ToList();
var updateHandle = new UpdateService();
while (true)
if (lstSubs is not { Count: > 0 })
{
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = (await AppHandler.Instance.SubItems())
.Where(t => t.AutoUpdateInterval > 0)
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
.ToList();
return;
}
foreach (var item in lstSubs)
Logging.SaveLog("Execute update subscription");
var updateHandle = new UpdateService();
foreach (var item in lstSubs)
{
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
{
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
{
updateFunc?.Invoke(success, msg);
if (success)
Logging.SaveLog("subscription" + msg);
});
item.UpdateTime = updateTime;
await ConfigHandler.AddSubItem(config, item);
await Task.Delay(5000);
}
await Task.Delay(60000);
updateFunc?.Invoke(success, msg);
if (success)
{
Logging.SaveLog($"Update subscription end. {msg}");
}
});
item.UpdateTime = updateTime;
await ConfigHandler.AddSubItem(config, item);
await Task.Delay(1000);
}
}
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> updateFunc)
private async Task UpdateTaskRunGeo(Config config, int hours, Action<bool, string> updateFunc)
{
var autoUpdateGeoTime = DateTime.Now;
//await Task.Delay(1000 * 120);
Logging.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateService();
while (true)
if (config.GuiItem.AutoUpdateInterval > 0 && hours > 0 && hours % config.GuiItem.AutoUpdateInterval == 0)
{
await Task.Delay(1000 * 3600);
Logging.SaveLog("Execute update geo files");
var dtNow = DateTime.Now;
if (config.GuiItem.AutoUpdateInterval > 0)
var updateHandle = new UpdateService();
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
if ((dtNow - autoUpdateGeoTime).Hours % config.GuiItem.AutoUpdateInterval == 0)
{
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
updateFunc?.Invoke(false, msg);
});
autoUpdateGeoTime = dtNow;
}
}
updateFunc?.Invoke(false, msg);
});
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Net;
using System.Net;
using WebDav;
namespace ServiceLib.Handler
@@ -8,12 +8,12 @@ namespace ServiceLib.Handler
private static readonly Lazy<WebDavHandler> _instance = new(() => new());
public static WebDavHandler Instance => _instance.Value;
private Config? _config;
private readonly Config? _config;
private WebDavClient? _client;
private string? _lastDescription;
private string _webDir = Global.AppName + "_backup";
private readonly string _webFileName = "backup.zip";
private string _logTitle = "WebDav--";
private readonly string _tag = "WebDav--";
public WebDavHandler()
{
@@ -61,7 +61,10 @@ namespace ServiceLib.Handler
private async Task<bool> TryCreateDir()
{
if (_client is null) return false;
if (_client is null)
{
return false;
}
try
{
var result2 = await _client.Mkcol(_webDir);
@@ -81,13 +84,13 @@ namespace ServiceLib.Handler
private void SaveLog(string desc)
{
_lastDescription = desc;
Logging.SaveLog(_logTitle + desc);
Logging.SaveLog(_tag + desc);
}
private void SaveLog(Exception ex)
{
_lastDescription = ex.Message;
Logging.SaveLog(_logTitle, ex);
Logging.SaveLog(_tag, ex);
}
public async Task<bool> CheckConnection()
@@ -176,4 +179,4 @@ namespace ServiceLib.Handler
public string GetLastError() => _lastDescription ?? string.Empty;
}
}
}

View File

@@ -29,7 +29,7 @@
public string? destinationPort { get; set; }
public string? host { get; set; }
public string? nsMode { get; set; }
public object uid { get; set; }
public object? uid { get; set; }
public string? process { get; set; }
public string? processPath { get; set; }
public string? remoteDestination { get; set; }

View File

@@ -20,6 +20,7 @@
case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
return true;
default:
return false;
}
@@ -46,6 +47,7 @@
public SystemProxyItem SystemProxyItem { get; set; }
public WebDavItem WebDavItem { get; set; }
public CheckUpdateItem CheckUpdateItem { get; set; }
public Fragment4RayItem? Fragment4RayItem { get; set; }
public List<InItem> Inbound { get; set; }
public List<KeyEventItem> GlobalHotkeys { get; set; }
public List<CoreTypeItem> CoreTypeItem { get; set; }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Models
namespace ServiceLib.Models
{
[Serializable]
public class CoreBasicItem
@@ -24,21 +24,16 @@
public class InItem
{
public int LocalPort { get; set; }
public string Protocol { get; set; }
public bool UdpEnabled { get; set; }
public bool SniffingEnabled { get; set; } = true;
public List<string>? DestOverride { get; set; } = ["http", "tls"];
public bool RouteOnly { get; set; }
public bool AllowLANConn { get; set; }
public bool NewPort4LAN { get; set; }
public string User { get; set; }
public string Pass { get; set; }
public bool SecondLocalPortEnabled { get; set; }
}
[Serializable]
@@ -72,21 +67,13 @@
public class GUIItem
{
public bool AutoRun { get; set; }
public bool EnableStatistics { get; set; }
public bool DisplayRealTimeSpeed { get; set; }
public bool KeepOlderDedupl { get; set; }
public bool IgnoreGeoUpdateCore { get; set; } = true;
public int AutoUpdateInterval { get; set; }
public bool EnableSecurityProtocolTls13 { get; set; }
public int TrayMenuServersLimit { get; set; } = 20;
public bool EnableHWA { get; set; } = false;
public bool EnableLog { get; set; } = true;
}
@@ -107,15 +94,15 @@
public double MainGirdHeight1 { get; set; }
public double MainGirdHeight2 { get; set; }
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
public bool ColorModeDark { get; set; }
public bool FollowSystemTheme { get; set; }
public string? ColorPrimaryName { get; set; }
public string? CurrentTheme { get; set; }
public string CurrentLanguage { get; set; }
public string CurrentFontFamily { get; set; }
public int CurrentFontSize { get; set; }
public bool EnableDragDropSort { get; set; }
public bool DoubleClick2Activate { get; set; }
public bool AutoHideStartup { get; set; }
public bool Hide2TrayWhenClose { get; set; }
public List<ColumnItem> MainColumnItem { get; set; }
public bool ShowInTaskbar { get; set; }
}
@@ -123,8 +110,7 @@
[Serializable]
public class ConstItem
{
public string DefIEProxyExceptions { get; set; }
public string SubConvertUrl { get; set; } = string.Empty;
public string? SubConvertUrl { get; set; }
public string? GeoSourceUrl { get; set; }
public string? SrsSourceUrl { get; set; }
public string? RouteRulesTemplateSourceUrl { get; set; }
@@ -161,6 +147,7 @@
public int Mtu { get; set; }
public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPwd { get; set; }
}
[Serializable]
@@ -169,6 +156,7 @@
public int SpeedTestTimeout { get; set; }
public string SpeedTestUrl { get; set; }
public string SpeedPingTestUrl { get; set; }
public int MixedConcurrencyCount { get; set; }
}
[Serializable]
@@ -178,7 +166,6 @@
public string DomainStrategy4Singbox { get; set; }
public string DomainMatcher { get; set; }
public string RoutingIndexId { get; set; }
public bool EnableRoutingAdvanced { get; set; }
}
[Serializable]
@@ -210,6 +197,7 @@
{
public int UpMbps { get; set; }
public int DownMbps { get; set; }
public int HopInterval { get; set; } = 30;
}
[Serializable]
@@ -221,7 +209,6 @@
public int ProxiesSorting { get; set; }
public bool ProxiesAutoRefresh { get; set; }
public int ProxiesAutoDelayTestInterval { get; set; } = 10;
public int ConnectionsSorting { get; set; }
public bool ConnectionsAutoRefresh { get; set; }
public int ConnectionsRefreshInterval { get; set; } = 2;
}
@@ -250,4 +237,12 @@
public bool CheckPreReleaseUpdate { get; set; }
public List<string>? SelectedCoreTypes { get; set; }
}
}
[Serializable]
public class Fragment4RayItem
{
public string? Packets { get; set; }
public string? Length { get; set; }
public string? Interval { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Models
namespace ServiceLib.Models
{
[Serializable]
public class CoreInfo
@@ -12,8 +12,10 @@
public string? DownloadUrlWinArm64 { get; set; }
public string? DownloadUrlLinux64 { get; set; }
public string? DownloadUrlLinuxArm64 { get; set; }
public string? DownloadUrlOSX64 { get; set; }
public string? DownloadUrlOSXArm64 { get; set; }
public string? Match { get; set; }
public string? VersionArg { get; set; }
public bool RedirectInfo { get; set; }
public bool AbsolutePath { get; set; }
}
}
}

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
using SQLite;
using SQLite;
namespace ServiceLib.Models
{
@@ -30,49 +30,30 @@ namespace ServiceLib.Models
public string GetSummary()
{
string summary = string.Format("[{0}] ", (ConfigType).ToString());
string[] arrAddr = Address.Split('.');
string addr;
if (arrAddr.Length > 2)
var summary = $"[{(ConfigType).ToString()}] ";
var arrAddr = Address.Split('.');
var addr = arrAddr.Length switch
{
addr = $"{arrAddr.First()}***{arrAddr.Last()}";
}
else if (arrAddr.Length > 1)
> 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
> 1 => $"***{arrAddr.Last()}",
_ => Address
};
summary += ConfigType switch
{
addr = $"***{arrAddr.Last()}";
}
else
{
addr = Address;
}
switch (ConfigType)
{
case EConfigType.Custom:
summary += string.Format("[{1}]{0}", Remarks, CoreType.ToString());
break;
default:
summary += string.Format("{0}({1}:{2})", Remarks, addr, Port);
break;
}
EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}",
_ => $"{Remarks}({addr}:{Port})"
};
return summary;
}
public List<string>? GetAlpn()
{
if (Utils.IsNullOrEmpty(Alpn))
{
return null;
}
else
{
return Utils.String2List(Alpn);
}
return Alpn.IsNullOrEmpty() ? null : Utils.String2List(Alpn);
}
public string GetNetwork()
{
if (Utils.IsNullOrEmpty(Network) || !Global.Networks.Contains(Network))
if (Network.IsNullOrEmpty() || !Global.Networks.Contains(Network))
{
return Global.DefaultNetwork;
}
@@ -83,11 +64,11 @@ namespace ServiceLib.Models
[PrimaryKey]
public string IndexId { get; set; }
public EConfigType ConfigType { get; set; }
public int ConfigVersion { get; set; }
public string Address { get; set; }
public int Port { get; set; }
public string Ports { get; set; }
public string Id { get; set; }
public int AlterId { get; set; }
public string Security { get; set; }
@@ -110,5 +91,6 @@ namespace ServiceLib.Models
public string PublicKey { get; set; }
public string ShortId { get; set; }
public string SpiderX { get; set; }
public string Extra { get; set; }
}
}
}

View File

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

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Models
namespace ServiceLib.Models
{
public class SingboxConfig
{
@@ -78,8 +78,7 @@
public int? listen_port { get; set; }
public string? domain_strategy { get; set; }
public string interface_name { get; set; }
public string inet4_address { get; set; }
public string? inet6_address { get; set; }
public List<string>? address { get; set; }
public int? mtu { get; set; }
public bool? auto_route { get; set; }
public bool? strict_route { get; set; }
@@ -102,21 +101,23 @@
public string tag { get; set; }
public string? server { get; set; }
public int? server_port { get; set; }
public string uuid { get; set; }
public string security { get; set; }
public List<string>? server_ports { get; set; }
public string? uuid { get; set; }
public string? security { get; set; }
public int? alter_id { get; set; }
public string flow { get; set; }
public string? flow { get; set; }
public string? hop_interval { get; set; }
public int? up_mbps { get; set; }
public int? down_mbps { get; set; }
public string auth_str { get; set; }
public string? auth_str { get; set; }
public int? recv_window_conn { get; set; }
public int? recv_window { get; set; }
public bool? disable_mtu_discovery { get; set; }
public string? detour { get; set; }
public string method { get; set; }
public string username { get; set; }
public string password { get; set; }
public string congestion_control { get; set; }
public string? method { get; set; }
public string? username { get; set; }
public string? password { get; set; }
public string? congestion_control { get; set; }
public string? version { get; set; }
public string? network { get; set; }
public string? packet_encoding { get; set; }
@@ -253,4 +254,4 @@
public string? download_detour { get; set; }
public string? update_interval { get; set; }
}
}
}

View File

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

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