├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── 01_bug_report.yml │ └── 02_feature_request.yml ├── dependabot.yml └── workflows │ ├── build-all.yml │ ├── build-linux.yml │ ├── build-osx.yml │ ├── build-windows-desktop.yml │ ├── build-windows.yml │ └── winget-publish.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── package-appimage.sh ├── package-debian.sh ├── package-osx.sh ├── package-release-zip.sh ├── pkg2appimage.yml └── v2rayN ├── AmazTool ├── AmazTool.csproj ├── Program.cs ├── Resx │ ├── Resource.Designer.cs │ ├── Resource.resx │ ├── Resource.zh-Hans.resx │ └── Resource.zh-Hant.resx ├── UpgradeApp.cs └── Utils.cs ├── Directory.Build.props ├── Directory.Packages.props ├── ServiceLib ├── Base │ └── MyReactiveObject.cs ├── Common │ ├── AesUtils.cs │ ├── DesUtils.cs │ ├── DownloaderHelper.cs │ ├── EmbedUtils.cs │ ├── FileManager.cs │ ├── HttpClientHelper.cs │ ├── Job.cs │ ├── JsonUtils.cs │ ├── Logging.cs │ ├── ProcUtils.cs │ ├── QRCodeHelper.cs │ ├── SemanticVersion.cs │ ├── SqliteHelper.cs │ ├── StringEx.cs │ ├── Utils.cs │ ├── WindowsUtils.cs │ └── YamlUtils.cs ├── Enums │ ├── EConfigType.cs │ ├── ECoreType.cs │ ├── EGirdOrientation.cs │ ├── EGlobalHotkey.cs │ ├── EInboundProtocol.cs │ ├── EMove.cs │ ├── EMsgCommand.cs │ ├── EMultipleLoad.cs │ ├── EPresetType.cs │ ├── ERuleMode.cs │ ├── EServerColName.cs │ ├── ESpeedActionType.cs │ ├── ESysProxyType.cs │ ├── ETheme.cs │ ├── ETransport.cs │ └── EViewAction.cs ├── FodyWeavers.xml ├── Global.cs ├── GlobalUsings.cs ├── Handler │ ├── AppHandler.cs │ ├── AutoStartupHandler.cs │ ├── ClashApiHandler.cs │ ├── ConfigHandler.cs │ ├── ConnectionHandler.cs │ ├── CoreAdminHandler.cs │ ├── CoreConfigHandler.cs │ ├── CoreHandler.cs │ ├── CoreInfoHandler.cs │ ├── Fmt │ │ ├── BaseFmt.cs │ │ ├── ClashFmt.cs │ │ ├── FmtHandler.cs │ │ ├── Hysteria2Fmt.cs │ │ ├── NaiveproxyFmt.cs │ │ ├── ShadowsocksFmt.cs │ │ ├── SingboxFmt.cs │ │ ├── SocksFmt.cs │ │ ├── TrojanFmt.cs │ │ ├── TuicFmt.cs │ │ ├── V2rayFmt.cs │ │ ├── VLESSFmt.cs │ │ ├── VmessFmt.cs │ │ └── WireguardFmt.cs │ ├── NoticeHandler.cs │ ├── PacHandler.cs │ ├── ProfileExHandler.cs │ ├── StatisticsHandler.cs │ ├── SysProxy │ │ ├── ProxySettingLinux.cs │ │ ├── ProxySettingOSX.cs │ │ ├── ProxySettingWindows.cs │ │ └── SysProxyHandler.cs │ ├── TaskHandler.cs │ └── WebDavHandler.cs ├── Models │ ├── CheckUpdateModel.cs │ ├── ClashConnectionModel.cs │ ├── ClashConnections.cs │ ├── ClashProviders.cs │ ├── ClashProxies.cs │ ├── ClashProxyModel.cs │ ├── CmdItem.cs │ ├── ComboItem.cs │ ├── Config.cs │ ├── ConfigItems.cs │ ├── CoreInfo.cs │ ├── DNSItem.cs │ ├── GitHubRelease.cs │ ├── IPAPIInfo.cs │ ├── ProfileExItem.cs │ ├── ProfileItem.cs │ ├── ProfileItemModel.cs │ ├── RetResult.cs │ ├── RoutingItem.cs │ ├── RoutingItemModel.cs │ ├── RoutingTemplate.cs │ ├── RulesItem.cs │ ├── RulesItemModel.cs │ ├── ServerSpeedItem.cs │ ├── ServerStatItem.cs │ ├── ServerTestItem.cs │ ├── SingboxConfig.cs │ ├── SpeedTestResult.cs │ ├── SsSIP008.cs │ ├── SubItem.cs │ ├── V2rayConfig.cs │ ├── V2rayMetricsVars.cs │ ├── V2rayTcpRequest.cs │ └── VmessQRCode.cs ├── Resx │ ├── ResUI.Designer.cs │ ├── ResUI.fa-Ir.resx │ ├── ResUI.hu.resx │ ├── ResUI.resx │ ├── ResUI.ru.resx │ ├── ResUI.zh-Hans.resx │ └── ResUI.zh-Hant.resx ├── Sample │ ├── SampleClientConfig │ ├── SampleHttpRequest │ ├── SampleHttpResponse │ ├── SampleInbound │ ├── SampleOutbound │ ├── SingboxSampleClientConfig │ ├── SingboxSampleOutbound │ ├── clash_mixin_yaml │ ├── clash_tun_yaml │ ├── custom_routing_black │ ├── custom_routing_global │ ├── custom_routing_white │ ├── dns_singbox_normal │ ├── dns_v2ray_normal │ ├── linux_autostart_config │ ├── pac │ ├── proxy_set_linux_sh │ ├── proxy_set_osx_sh │ ├── tun_singbox_dns │ ├── tun_singbox_inbound │ └── tun_singbox_rules ├── ServiceLib.csproj ├── Services │ ├── CoreConfig │ │ ├── CoreConfigClashService.cs │ │ ├── CoreConfigSingboxService.cs │ │ └── CoreConfigV2rayService.cs │ ├── DownloadService.cs │ ├── SpeedtestService.cs │ ├── Statistics │ │ ├── StatisticsSingboxService.cs │ │ └── StatisticsXrayService.cs │ └── UpdateService.cs └── ViewModels │ ├── AddServer2ViewModel.cs │ ├── AddServerViewModel.cs │ ├── BackupAndRestoreViewModel.cs │ ├── CheckUpdateViewModel.cs │ ├── ClashConnectionsViewModel.cs │ ├── ClashProxiesViewModel.cs │ ├── DNSSettingViewModel.cs │ ├── GlobalHotkeySettingViewModel.cs │ ├── MainWindowViewModel.cs │ ├── MsgViewModel.cs │ ├── OptionSettingViewModel.cs │ ├── ProfilesViewModel.cs │ ├── RoutingRuleDetailsViewModel.cs │ ├── RoutingRuleSettingViewModel.cs │ ├── RoutingSettingViewModel.cs │ ├── StatusBarViewModel.cs │ ├── SubEditViewModel.cs │ └── SubSettingViewModel.cs ├── v2rayN.Desktop ├── App.axaml ├── App.axaml.cs ├── Assets │ ├── Fonts │ │ └── NotoSansSC-Regular.ttf │ ├── GlobalResources.axaml │ ├── GlobalStyles.axaml │ ├── NotifyIcon1.ico │ ├── NotifyIcon2.ico │ ├── NotifyIcon3.ico │ ├── NotifyIcon4.ico │ └── v2rayN.ico ├── Common │ ├── AppBuilderExtension.cs │ ├── AvaUtils.cs │ └── UI.cs ├── Controls │ ├── AutoCompleteBox.axaml │ └── AutoCompleteBox.cs ├── Converters │ └── DelayColorConverter.cs ├── FodyWeavers.xml ├── GlobalUsings.cs ├── Handler │ └── HotkeyHandler.cs ├── Program.cs ├── ViewModels │ └── ThemeSettingViewModel.cs ├── Views │ ├── AddServer2Window.axaml │ ├── AddServer2Window.axaml.cs │ ├── AddServerWindow.axaml │ ├── AddServerWindow.axaml.cs │ ├── BackupAndRestoreView.axaml │ ├── BackupAndRestoreView.axaml.cs │ ├── CheckUpdateView.axaml │ ├── CheckUpdateView.axaml.cs │ ├── ClashConnectionsView.axaml │ ├── ClashConnectionsView.axaml.cs │ ├── ClashProxiesView.axaml │ ├── ClashProxiesView.axaml.cs │ ├── DNSSettingWindow.axaml │ ├── DNSSettingWindow.axaml.cs │ ├── GlobalHotkeySettingWindow.axaml │ ├── GlobalHotkeySettingWindow.axaml.cs │ ├── MainWindow.axaml │ ├── MainWindow.axaml.cs │ ├── MsgView.axaml │ ├── MsgView.axaml.cs │ ├── OptionSettingWindow.axaml │ ├── OptionSettingWindow.axaml.cs │ ├── ProfilesView.axaml │ ├── ProfilesView.axaml.cs │ ├── QrcodeView.axaml │ ├── QrcodeView.axaml.cs │ ├── RoutingRuleDetailsWindow.axaml │ ├── RoutingRuleDetailsWindow.axaml.cs │ ├── RoutingRuleSettingWindow.axaml │ ├── RoutingRuleSettingWindow.axaml.cs │ ├── RoutingSettingWindow.axaml │ ├── RoutingSettingWindow.axaml.cs │ ├── StatusBarView.axaml │ ├── StatusBarView.axaml.cs │ ├── SubEditWindow.axaml │ ├── SubEditWindow.axaml.cs │ ├── SubSettingWindow.axaml │ ├── SubSettingWindow.axaml.cs │ ├── SudoPasswordInputView.axaml │ ├── SudoPasswordInputView.axaml.cs │ ├── ThemeSettingView.axaml │ └── ThemeSettingView.axaml.cs ├── v2rayN.Desktop.csproj ├── v2rayN.icns └── v2rayN.png ├── v2rayN.sln └── v2rayN ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── Base └── MyDGTextColumn.cs ├── Common ├── QRCodeHelper.cs ├── UI.cs └── WindowsUtils.cs ├── Converters ├── DelayColorConverter.cs ├── InverseBooleanConverter.cs └── MaterialDesignFonts.cs ├── FodyWeavers.xml ├── GlobalUsings.cs ├── Handler ├── HotkeyHandler.cs └── WindowsHandler.cs ├── Properties ├── Resources.Designer.cs └── Resources.resx ├── Resources ├── NotifyIcon1.ico ├── NotifyIcon2.ico ├── NotifyIcon3.ico ├── NotifyIcon4.ico └── v2rayN.ico ├── ViewModels └── ThemeSettingViewModel.cs ├── Views ├── AddServer2Window.xaml ├── AddServer2Window.xaml.cs ├── AddServerWindow.xaml ├── AddServerWindow.xaml.cs ├── BackupAndRestoreView.xaml ├── BackupAndRestoreView.xaml.cs ├── CheckUpdateView.xaml ├── CheckUpdateView.xaml.cs ├── ClashConnectionsView.xaml ├── ClashConnectionsView.xaml.cs ├── ClashProxiesView.xaml ├── ClashProxiesView.xaml.cs ├── DNSSettingWindow.xaml ├── DNSSettingWindow.xaml.cs ├── GlobalHotkeySettingWindow.xaml ├── GlobalHotkeySettingWindow.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MsgView.xaml ├── MsgView.xaml.cs ├── OptionSettingWindow.xaml ├── OptionSettingWindow.xaml.cs ├── ProfilesView.xaml ├── ProfilesView.xaml.cs ├── QrcodeView.xaml ├── QrcodeView.xaml.cs ├── RoutingRuleDetailsWindow.xaml ├── RoutingRuleDetailsWindow.xaml.cs ├── RoutingRuleSettingWindow.xaml ├── RoutingRuleSettingWindow.xaml.cs ├── RoutingSettingWindow.xaml ├── RoutingSettingWindow.xaml.cs ├── StatusBarView.xaml ├── StatusBarView.xaml.cs ├── SubEditWindow.xaml ├── SubEditWindow.xaml.cs ├── SubSettingWindow.xaml ├── SubSettingWindow.xaml.cs ├── ThemeSettingView.xaml └── ThemeSettingView.xaml.cs ├── app.manifest └── v2rayN.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/01_bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug 报告 2 | description: 在提出问题前请先自行排除服务器端问题和升级到最新客户端,同时也请通过搜索确认是否有人提出过相同问题。 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: input 7 | id: "os-version" 8 | attributes: 9 | label: "操作系统和版本" 10 | description: "操作系统和版本" 11 | validations: 12 | required: true 13 | - type: input 14 | id: "expectation" 15 | attributes: 16 | label: "预期情况" 17 | description: "描述你认为应该发生什么" 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: "describe-the-bug" 22 | attributes: 23 | label: "实际情况" 24 | description: "描述实际发生了什么" 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: "reproduction-method" 29 | attributes: 30 | label: "复现方法" 31 | description: "在BUG出现前执行了哪些操作" 32 | placeholder: 标序号 33 | validations: 34 | required: true 35 | - type: textarea 36 | id: "log" 37 | attributes: 38 | label: "日志信息" 39 | description: "位置在软件当前目录下的guiLogs" 40 | placeholder: 在日志开始和结束位置粘贴冒号后的内容:``` 41 | validations: 42 | required: true 43 | - type: textarea 44 | id: "more" 45 | attributes: 46 | label: "额外信息" 47 | description: "可选" 48 | validations: 49 | required: false 50 | - type: checkboxes 51 | id: "latest-version" 52 | attributes: 53 | label: "我确认已更新至最新版本" 54 | description: "否则请更新后尝试" 55 | options: 56 | - label: 是 57 | required: true 58 | - type: checkboxes 59 | id: "issues" 60 | attributes: 61 | label: "我确认已查询历史issues" 62 | description: "否则请查询后提出" 63 | options: 64 | - label: 是 65 | required: true 66 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature 请求 2 | description: "为这个项目提出一个建议" 3 | title: "[Feature request]: " 4 | labels: ['enhancement'] 5 | body: 6 | - type: input 7 | id: problem 8 | attributes: 9 | label: 相关问题 10 | description: "清楚而简洁地描述问题是什么。" 11 | placeholder: "当我想要……时,软件不能……" 12 | validations: 13 | required: true 14 | - type: input 15 | id: way-to-solve 16 | attributes: 17 | label: 描述你希望的解决方案 18 | description: "你希望发生什么" 19 | validations: 20 | required: true 21 | - type: input 22 | id: instead 23 | attributes: 24 | label: 描述你所考虑的替代方案 25 | validations: 26 | required: false 27 | - type: checkboxes 28 | id: "issues" 29 | attributes: 30 | label: "我确认已查询历史issues" 31 | description: "否则请查询后提出" 32 | options: 33 | - label: 是 34 | required: true 35 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "nuget" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/build-all.yml: -------------------------------------------------------------------------------- 1 | name: release all platforms 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_tag: 7 | required: false 8 | type: string 9 | 10 | jobs: 11 | update: 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - name: Trigger build windows 16 | if: github.event.inputs.release_tag != '' 17 | run: | 18 | curl -X POST \ 19 | -H "Accept: application/vnd.github.v3+json" \ 20 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ 21 | https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows.yml/dispatches \ 22 | -d "{ 23 | \"ref\": \"master\", 24 | \"inputs\": { 25 | \"release_tag\": \"${{ github.event.inputs.release_tag }}\" 26 | } 27 | }" 28 | 29 | - name: Trigger build linux 30 | if: github.event.inputs.release_tag != '' 31 | run: | 32 | curl -X POST \ 33 | -H "Accept: application/vnd.github.v3+json" \ 34 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ 35 | https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-linux.yml/dispatches \ 36 | -d "{ 37 | \"ref\": \"master\", 38 | \"inputs\": { 39 | \"release_tag\": \"${{ github.event.inputs.release_tag }}\" 40 | } 41 | }" 42 | 43 | - name: Trigger build osx 44 | if: github.event.inputs.release_tag != '' 45 | run: | 46 | curl -X POST \ 47 | -H "Accept: application/vnd.github.v3+json" \ 48 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ 49 | https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-osx.yml/dispatches \ 50 | -d "{ 51 | \"ref\": \"master\", 52 | \"inputs\": { 53 | \"release_tag\": \"${{ github.event.inputs.release_tag }}\" 54 | } 55 | }" 56 | 57 | - name: Trigger build windows desktop 58 | if: github.event.inputs.release_tag != '' 59 | run: | 60 | curl -X POST \ 61 | -H "Accept: application/vnd.github.v3+json" \ 62 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ 63 | https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows-desktop.yml/dispatches \ 64 | -d "{ 65 | \"ref\": \"master\", 66 | \"inputs\": { 67 | \"release_tag\": \"${{ github.event.inputs.release_tag }}\" 68 | } 69 | }" -------------------------------------------------------------------------------- /.github/workflows/build-osx.yml: -------------------------------------------------------------------------------- 1 | name: release macOS 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_tag: 7 | required: false 8 | type: string 9 | push: 10 | branches: 11 | - master 12 | 13 | env: 14 | OutputArch: "macos-64" 15 | OutputArchArm: "macos-arm64" 16 | OutputPath64: "${{ github.workspace }}/v2rayN/Release/macos-64" 17 | OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/macos-arm64" 18 | 19 | jobs: 20 | build: 21 | strategy: 22 | matrix: 23 | configuration: [Release] 24 | 25 | runs-on: macos-latest 26 | 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v4.2.2 30 | with: 31 | submodules: 'recursive' 32 | fetch-depth: '0' 33 | 34 | - name: Setup 35 | uses: actions/setup-dotnet@v4.3.1 36 | with: 37 | dotnet-version: '8.0.x' 38 | 39 | - name: Build 40 | run: | 41 | cd v2rayN 42 | dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained=true -o $OutputPath64 43 | dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained=true -o $OutputPathArm64 44 | dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64 45 | dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64 46 | 47 | - name: Upload build artifacts 48 | uses: actions/upload-artifact@v4.6.2 49 | with: 50 | name: v2rayN-macos 51 | path: | 52 | ${{ github.workspace }}/v2rayN/Release/macos* 53 | 54 | # release osx package 55 | - name: Package osx 56 | if: github.event.inputs.release_tag != '' 57 | run: | 58 | brew install create-dmg 59 | chmod 755 package-osx.sh 60 | ./package-osx.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }} 61 | ./package-osx.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }} 62 | 63 | - name: Upload dmg to release 64 | uses: svenstaro/upload-release-action@v2 65 | if: github.event.inputs.release_tag != '' 66 | with: 67 | file: ${{ github.workspace }}/v2rayN*.dmg 68 | tag: ${{ github.event.inputs.release_tag }} 69 | file_glob: true 70 | prerelease: true 71 | 72 | # release zip archive 73 | - name: Package release zip archive 74 | if: github.event.inputs.release_tag != '' 75 | run: | 76 | chmod 755 package-release-zip.sh 77 | ./package-release-zip.sh $OutputArch $OutputPath64 78 | ./package-release-zip.sh $OutputArchArm $OutputPathArm64 79 | 80 | - name: Upload zip archive to release 81 | uses: svenstaro/upload-release-action@v2 82 | if: github.event.inputs.release_tag != '' 83 | with: 84 | file: ${{ github.workspace }}/v2rayN*.zip 85 | tag: ${{ github.event.inputs.release_tag }} 86 | file_glob: true 87 | prerelease: true -------------------------------------------------------------------------------- /.github/workflows/build-windows-desktop.yml: -------------------------------------------------------------------------------- 1 | name: release Windows desktop (Avalonia UI) 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_tag: 7 | required: false 8 | type: string 9 | push: 10 | branches: 11 | - master 12 | 13 | env: 14 | OutputArch: "windows-64" 15 | OutputArchArm: "windows-arm64" 16 | OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64" 17 | OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64" 18 | 19 | jobs: 20 | build: 21 | strategy: 22 | matrix: 23 | configuration: [Release] 24 | 25 | runs-on: ubuntu-latest 26 | 27 | steps: 28 | - name: Checkout 29 | uses: actions/checkout@v4.2.2 30 | with: 31 | submodules: 'recursive' 32 | fetch-depth: '0' 33 | 34 | - name: Setup 35 | uses: actions/setup-dotnet@v4.3.1 36 | with: 37 | dotnet-version: '8.0.x' 38 | 39 | - name: Build 40 | run: | 41 | cd v2rayN 42 | dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64 43 | dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64 44 | dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64 45 | dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64 46 | 47 | - name: Upload build artifacts 48 | uses: actions/upload-artifact@v4.6.2 49 | with: 50 | name: v2rayN-windows-desktop 51 | path: | 52 | ${{ github.workspace }}/v2rayN/Release/windows* 53 | 54 | # release zip archive 55 | - name: Package release zip archive 56 | if: github.event.inputs.release_tag != '' 57 | run: | 58 | chmod 755 package-release-zip.sh 59 | ./package-release-zip.sh $OutputArch $OutputPath64 60 | mv "v2rayN-${OutputArch}.zip" "v2rayN-${OutputArch}-desktop.zip" 61 | ./package-release-zip.sh $OutputArchArm $OutputPathArm64 62 | mv "v2rayN-${OutputArchArm}.zip" "v2rayN-${OutputArchArm}-desktop.zip" 63 | 64 | - name: Upload zip archive to release 65 | uses: svenstaro/upload-release-action@v2 66 | if: github.event.inputs.release_tag != '' 67 | with: 68 | file: ${{ github.workspace }}/v2rayN*.zip 69 | tag: ${{ github.event.inputs.release_tag }} 70 | file_glob: true 71 | prerelease: true 72 | -------------------------------------------------------------------------------- /.github/workflows/build-windows.yml: -------------------------------------------------------------------------------- 1 | name: release Windows 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_tag: 7 | required: false 8 | type: string 9 | push: 10 | branches: 11 | - master 12 | 13 | env: 14 | OutputArch: "windows-64" 15 | OutputArchArm: "windows-arm64" 16 | OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64" 17 | OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64" 18 | OutputPath64Sc: "${{ github.workspace }}/v2rayN/Release/windows-64-SelfContained" 19 | 20 | jobs: 21 | build: 22 | strategy: 23 | matrix: 24 | configuration: [Release] 25 | 26 | runs-on: ubuntu-latest 27 | 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4.2.2 31 | 32 | - name: Setup 33 | uses: actions/setup-dotnet@v4.3.1 34 | with: 35 | dotnet-version: '8.0.x' 36 | 37 | - name: Build 38 | run: | 39 | cd v2rayN 40 | dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64 41 | dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64 42 | dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc 43 | dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64 44 | dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64 45 | dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc 46 | 47 | 48 | - name: Upload build artifacts 49 | uses: actions/upload-artifact@v4.6.2 50 | with: 51 | name: v2rayN-windows 52 | path: | 53 | ${{ github.workspace }}/v2rayN/Release/windows* 54 | 55 | # release zip archive 56 | - name: Package release zip archive 57 | if: github.event.inputs.release_tag != '' 58 | run: | 59 | chmod 755 package-release-zip.sh 60 | ./package-release-zip.sh $OutputArch $OutputPath64 61 | ./package-release-zip.sh $OutputArchArm $OutputPathArm64 62 | ./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc 63 | 64 | - name: Upload zip archive to release 65 | uses: svenstaro/upload-release-action@v2 66 | if: github.event.inputs.release_tag != '' 67 | with: 68 | file: ${{ github.workspace }}/v2rayN*.zip 69 | tag: ${{ github.event.inputs.release_tag }} 70 | file_glob: true 71 | prerelease: true -------------------------------------------------------------------------------- /.github/workflows/winget-publish.yml: -------------------------------------------------------------------------------- 1 | name: WinGet submission on release 2 | # based off of https://github.com/nushell/nushell/blob/main/.github/workflows/winget-submission.yml 3 | # inspired by https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml 4 | # Modified by @MerrickZ https://github.com/anpho 5 | 6 | on: 7 | workflow_dispatch: 8 | release: 9 | types: [released] 10 | 11 | jobs: 12 | winget: 13 | name: Publish winget package 14 | runs-on: windows-latest 15 | steps: 16 | - name: Submit v2ray package to Windows Package Manager Community Repository 17 | run: | 18 | 19 | $wingetPackage = "2dust.v2rayN" 20 | $gitToken = "${{ secrets.PT_WINGET }}" 21 | 22 | $github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases" 23 | 24 | $targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1 25 | $installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip*' | Select -ExpandProperty browser_download_url 26 | 27 | $ver = $targetRelease.tag_name 28 | 29 | # getting latest wingetcreate file 30 | iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe 31 | .\wingetcreate.exe update $wingetPackage -s -v $ver -u "$installerUrl|x64" -t $gitToken 32 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "v2rayN/GlobalHotKeys"] 2 | path = v2rayN/GlobalHotKeys 3 | url = https://github.com/2dust/GlobalHotKeys 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # v2rayN 2 | 3 | A GUI client for Windows, Linux and macOS, support [Xray](https://github.com/XTLS/Xray-core) 4 | and [sing-box](https://github.com/SagerNet/sing-box) 5 | and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) 6 | 7 | [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master) 8 | [![CodeFactor](https://www.codefactor.io/repository/github/2dust/v2rayn/badge)](https://www.codefactor.io/repository/github/2dust/v2rayn) 9 | [![GitHub Releases](https://img.shields.io/github/downloads/2dust/v2rayN/latest/total?logo=github)](https://github.com/2dust/v2rayN/releases) 10 | [![Chat on Telegram](https://img.shields.io/badge/Chat%20on-Telegram-brightgreen.svg)](https://t.me/v2rayn) 11 | 12 | ## How to use 13 | 14 | Read the [Wiki](https://github.com/2dust/v2rayN/wiki) for details. 15 | 16 | ## Telegram Channel 17 | 18 | [github_2dust](https://t.me/github_2dust) 19 | -------------------------------------------------------------------------------- /package-appimage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo apt update -y 4 | sudo apt install -y libfuse2 5 | wget -O pkg2appimage https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage 6 | chmod a+x pkg2appimage 7 | export AppImageOutputArch=$OutputArch 8 | export OutputPath=$OutputPath64 9 | ./pkg2appimage ./pkg2appimage.yml 10 | mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage 11 | export AppImageOutputArch=$OutputArchArm 12 | export OutputPath=$OutputPathArm64 13 | ./pkg2appimage ./pkg2appimage.yml 14 | mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage 15 | -------------------------------------------------------------------------------- /package-debian.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | Arch="$1" 4 | OutputPath="$2" 5 | Version="$3" 6 | 7 | FileName="v2rayN-${Arch}.zip" 8 | wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName" 9 | 7z x $FileName 10 | cp -rf v2rayN-${Arch}/* $OutputPath 11 | 12 | PackagePath="v2rayN-Package-${Arch}" 13 | mkdir -p "${PackagePath}/DEBIAN" 14 | mkdir -p "${PackagePath}/opt" 15 | cp -rf $OutputPath "${PackagePath}/opt/v2rayN" 16 | echo "When this file exists, app will not store configs under this folder" > "${PackagePath}/opt/v2rayN/NotStoreConfigHere.txt" 17 | 18 | if [ $Arch = "linux-64" ]; then 19 | Arch2="amd64" 20 | else 21 | Arch2="arm64" 22 | fi 23 | echo $Arch2 24 | 25 | # basic 26 | cat >"${PackagePath}/DEBIAN/control" <<-EOF 27 | Package: v2rayN 28 | Version: $Version 29 | Architecture: $Arch2 30 | Maintainer: https://github.com/2dust/v2rayN 31 | Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others 32 | EOF 33 | 34 | cat >"${PackagePath}/DEBIAN/postinst" <<-EOF 35 | if [ ! -s /usr/share/applications/v2rayN.desktop ]; then 36 | cat >/usr/share/applications/v2rayN.desktop<<-END 37 | [Desktop Entry] 38 | Name=v2rayN 39 | Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others 40 | Exec=/opt/v2rayN/v2rayN 41 | Icon=/opt/v2rayN/v2rayN.png 42 | Terminal=false 43 | Type=Application 44 | Categories=Network;Application; 45 | END 46 | fi 47 | 48 | update-desktop-database 49 | EOF 50 | 51 | sudo chmod 0755 "${PackagePath}/DEBIAN/postinst" 52 | sudo chmod 0755 "${PackagePath}/opt/v2rayN/v2rayN" 53 | sudo chmod 0755 "${PackagePath}/opt/v2rayN/AmazTool" 54 | 55 | # desktop && PATH 56 | 57 | sudo dpkg-deb -Zxz --build $PackagePath 58 | sudo mv "${PackagePath}.deb" "v2rayN-${Arch}.deb" -------------------------------------------------------------------------------- /package-osx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | Arch="$1" 4 | OutputPath="$2" 5 | Version="$3" 6 | 7 | FileName="v2rayN-${Arch}.zip" 8 | wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName" 9 | 7z x $FileName 10 | cp -rf v2rayN-${Arch}/* $OutputPath 11 | 12 | PackagePath="v2rayN-Package-${Arch}" 13 | mkdir -p "$PackagePath/v2rayN.app/Contents/Resources" 14 | cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS" 15 | cp -f "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.icns" "$PackagePath/v2rayN.app/Contents/Resources/AppIcon.icns" 16 | echo "When this file exists, app will not store configs under this folder" > "$PackagePath/v2rayN.app/Contents/MacOS/NotStoreConfigHere.txt" 17 | chmod +x "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN" 18 | 19 | cat >"$PackagePath/v2rayN.app/Contents/Info.plist" <<-EOF 20 | 21 | 22 | 23 | 24 | CFBundleDevelopmentRegion 25 | English 26 | CFBundleDisplayName 27 | v2rayN 28 | CFBundleExecutable 29 | v2rayN 30 | CFBundleIconFile 31 | AppIcon 32 | CFBundleIconName 33 | AppIcon 34 | CFBundleIdentifier 35 | 2dust.v2rayN 36 | CFBundleName 37 | v2rayN 38 | CFBundlePackageType 39 | APPL 40 | CFBundleShortVersionString 41 | ${Version} 42 | CSResourcesFileMapped 43 | 44 | NSHighResolutionCapable 45 | 46 | 47 | 48 | EOF 49 | 50 | create-dmg \ 51 | --volname "v2rayN Installer" \ 52 | --window-size 700 420 \ 53 | --icon-size 100 \ 54 | --icon "v2rayN.app" 160 185 \ 55 | --hide-extension "v2rayN.app" \ 56 | --app-drop-link 500 185 \ 57 | "v2rayN-${Arch}.dmg" \ 58 | "$PackagePath/v2rayN.app" -------------------------------------------------------------------------------- /package-release-zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | Arch="$1" 4 | OutputPath="$2" 5 | 6 | OutputArch="v2rayN-${Arch}" 7 | FileName="v2rayN-${Arch}.zip" 8 | 9 | wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName" 10 | 11 | ZipPath64="./$OutputArch" 12 | mkdir $ZipPath64 13 | 14 | cp -rf $OutputPath "$ZipPath64/$OutputArch" 15 | 7z a -tZip $FileName "$ZipPath64/$OutputArch" -mx1 -------------------------------------------------------------------------------- /pkg2appimage.yml: -------------------------------------------------------------------------------- 1 | app: v2rayN 2 | binpatch: true 3 | 4 | ingredients: 5 | script: 6 | - export FileName="v2rayN-${AppImageOutputArch}.zip" 7 | - wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/${FileName}" 8 | - 7z x $FileName -aoa 9 | - cp -rf v2rayN-${AppImageOutputArch}/* $OutputPath 10 | 11 | script: 12 | - mkdir -p usr/bin usr/lib 13 | - cp -rf $OutputPath usr/lib/v2rayN 14 | - echo "When this file exists, app will not store configs under this folder" > usr/lib/v2rayN/NotStoreConfigHere.txt 15 | - ln -sf usr/lib/v2rayN/v2rayN usr/bin/v2rayN 16 | - chmod a+x usr/lib/v2rayN/v2rayN 17 | - find usr -type f -exec sh -c 'file "{}" | grep -qi "executable" && chmod +x "{}"' \; 18 | - install -Dm644 usr/lib/v2rayN/v2rayN.png v2rayN.png 19 | - install -Dm644 usr/lib/v2rayN/v2rayN.png usr/share/pixmaps/v2rayN.png 20 | - cat > v2rayN.desktop < AppRun <<\EOF 32 | - #!/bin/sh 33 | - HERE="$(dirname "$(readlink -f "${0}")")" 34 | - cd ${HERE}/usr/lib/v2rayN 35 | - exec ${HERE}/usr/lib/v2rayN/v2rayN $@ 36 | - EOF 37 | - chmod a+x AppRun 38 | -------------------------------------------------------------------------------- /v2rayN/AmazTool/AmazTool.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | 6 | 7 | 8 | 9 | ResXFileCodeGenerator 10 | Resource.Designer.cs 11 | 12 | 13 | 14 | True 15 | True 16 | Resource.resx 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /v2rayN/AmazTool/Program.cs: -------------------------------------------------------------------------------- 1 | namespace AmazTool; 2 | 3 | internal static class Program 4 | { 5 | [STAThread] 6 | private static void Main(string[] args) 7 | { 8 | try 9 | { 10 | // If no arguments are provided, display usage guidelines and exit 11 | if (args.Length == 0) 12 | { 13 | ShowHelp(); 14 | return; 15 | } 16 | 17 | // Log all arguments for debugging purposes 18 | foreach (var arg in args) 19 | { 20 | Console.WriteLine(arg); 21 | } 22 | 23 | // Parse command based on first argument 24 | switch (args[0].ToLowerInvariant()) 25 | { 26 | case "rebootas": 27 | // Handle application restart 28 | HandleRebootAsync(); 29 | break; 30 | 31 | case "help": 32 | case "--help": 33 | case "-h": 34 | case "/?": 35 | // Display help information 36 | ShowHelp(); 37 | break; 38 | 39 | default: 40 | // Default behavior: handle as upgrade data 41 | // Maintain backward compatibility with existing usage pattern 42 | var argData = Uri.UnescapeDataString(string.Join(" ", args)); 43 | HandleUpgrade(argData); 44 | break; 45 | } 46 | } 47 | catch (Exception ex) 48 | { 49 | // Global exception handling 50 | Console.WriteLine($"An error occurred: {ex.Message}"); 51 | Console.WriteLine("Press any key to exit..."); 52 | Console.ReadKey(); 53 | } 54 | } 55 | 56 | /// 57 | /// Display help information and usage guidelines 58 | /// 59 | private static void ShowHelp() 60 | { 61 | Console.WriteLine(Resx.Resource.Guidelines); 62 | Console.WriteLine("Available commands:"); 63 | Console.WriteLine(" rebootas - Restart the application"); 64 | Console.WriteLine(" help - Display this help information"); 65 | Thread.Sleep(5000); 66 | } 67 | 68 | /// 69 | /// Handle application restart 70 | /// 71 | private static void HandleRebootAsync() 72 | { 73 | Console.WriteLine("Restarting application..."); 74 | Thread.Sleep(1000); 75 | Utils.StartV2RayN(); 76 | } 77 | 78 | /// 79 | /// Handle application upgrade with the provided data 80 | /// 81 | /// Data for the upgrade process 82 | private static void HandleUpgrade(string upgradeData) 83 | { 84 | Console.WriteLine("Upgrading application..."); 85 | UpgradeApp.Upgrade(upgradeData); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /v2rayN/AmazTool/Utils.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace AmazTool; 4 | 5 | internal class Utils 6 | { 7 | public static string GetExePath() 8 | { 9 | return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty; 10 | } 11 | 12 | public static string StartupPath() 13 | { 14 | return AppDomain.CurrentDomain.BaseDirectory; 15 | } 16 | 17 | public static string GetPath(string fileName) 18 | { 19 | var startupPath = StartupPath(); 20 | if (string.IsNullOrEmpty(fileName)) 21 | { 22 | return startupPath; 23 | } 24 | return Path.Combine(startupPath, fileName); 25 | } 26 | 27 | public static string V2rayN => "v2rayN"; 28 | 29 | public static void StartV2RayN() 30 | { 31 | Process process = new() 32 | { 33 | StartInfo = new() 34 | { 35 | UseShellExecute = true, 36 | FileName = V2rayN, 37 | WorkingDirectory = StartupPath() 38 | } 39 | }; 40 | process.Start(); 41 | } 42 | 43 | public static void Waiting(int second) 44 | { 45 | for (var i = second; i > 0; i--) 46 | { 47 | Console.WriteLine(i); 48 | Thread.Sleep(1000); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /v2rayN/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7.12.5 5 | 6 | 7 | 8 | net8.0 9 | true 10 | true 11 | CA1031;CS1591;NU1507;CA1416;IDE0058 12 | annotations 13 | enable 14 | 2dust 15 | GPL-3.0 16 | Copyright © 2017-$([System.DateTime]::UtcNow.Year) $(Authors) 17 | false 18 | 19 | 20 | 21 | embedded 22 | false 23 | false 24 | false 25 | false 26 | false 27 | false 28 | 29 | true 30 | true 31 | false 32 | 33 | 34 | -------------------------------------------------------------------------------- /v2rayN/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Base/MyReactiveObject.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | namespace ServiceLib.Base; 4 | 5 | public class MyReactiveObject : ReactiveObject 6 | { 7 | protected static Config? _config; 8 | protected Func>? _updateView; 9 | } 10 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/DesUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Text; 3 | 4 | namespace ServiceLib.Common; 5 | 6 | public class DesUtils 7 | { 8 | /// 9 | /// Encrypt 10 | /// 11 | /// 12 | /// /// 13 | /// 14 | public static string Encrypt(string? text, string? key = null) 15 | { 16 | if (text.IsNullOrEmpty()) 17 | { 18 | return string.Empty; 19 | } 20 | GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv); 21 | var dsp = DES.Create(); 22 | using var memStream = new MemoryStream(); 23 | using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write); 24 | using var sWriter = new StreamWriter(cryStream); 25 | sWriter.Write(text); 26 | sWriter.Flush(); 27 | cryStream.FlushFinalBlock(); 28 | memStream.Flush(); 29 | return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length); 30 | } 31 | 32 | /// 33 | /// Decrypt 34 | /// 35 | /// 36 | /// 37 | /// 38 | public static string Decrypt(string? encryptText, string? key = null) 39 | { 40 | if (encryptText.IsNullOrEmpty()) 41 | { 42 | return string.Empty; 43 | } 44 | GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv); 45 | var dsp = DES.Create(); 46 | var buffer = Convert.FromBase64String(encryptText); 47 | 48 | using var memStream = new MemoryStream(); 49 | using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write); 50 | cryStream.Write(buffer, 0, buffer.Length); 51 | cryStream.FlushFinalBlock(); 52 | return Encoding.UTF8.GetString(memStream.ToArray()); 53 | } 54 | 55 | private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv) 56 | { 57 | if (key.IsNullOrEmpty()) 58 | { 59 | throw new ArgumentNullException("The key cannot be null"); 60 | } 61 | if (key.Length <= 8) 62 | { 63 | throw new ArgumentNullException("The key length cannot be less than 8 characters."); 64 | } 65 | 66 | rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8)); 67 | rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8)); 68 | } 69 | 70 | private static string GetDefaultKey() 71 | { 72 | return Utils.GetMd5(Utils.GetHomePath() + "DesUtils"); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/EmbedUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Reflection; 3 | 4 | namespace ServiceLib.Common; 5 | 6 | public static class EmbedUtils 7 | { 8 | private static readonly string _tag = "EmbedUtils"; 9 | private static readonly ConcurrentDictionary _dicEmbedCache = new(); 10 | 11 | /// 12 | /// Get embedded text resources 13 | /// 14 | /// 15 | /// 16 | public static string GetEmbedText(string res) 17 | { 18 | if (_dicEmbedCache.TryGetValue(res, out var value)) 19 | { 20 | return value; 21 | } 22 | var result = string.Empty; 23 | 24 | try 25 | { 26 | var assembly = Assembly.GetExecutingAssembly(); 27 | using var stream = assembly.GetManifestResourceStream(res); 28 | ArgumentNullException.ThrowIfNull(stream); 29 | using StreamReader reader = new(stream); 30 | result = reader.ReadToEnd(); 31 | } 32 | catch (Exception ex) 33 | { 34 | Logging.SaveLog(_tag, ex); 35 | } 36 | 37 | _dicEmbedCache.TryAdd(res, result); 38 | return result; 39 | } 40 | 41 | /// 42 | /// Get local storage resources 43 | /// 44 | /// 45 | public static string? LoadResource(string? res) 46 | { 47 | try 48 | { 49 | if (File.Exists(res)) 50 | { 51 | return File.ReadAllText(res); 52 | } 53 | } 54 | catch (Exception ex) 55 | { 56 | Logging.SaveLog(_tag, ex); 57 | } 58 | 59 | return null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/Logging.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using NLog.Config; 3 | using NLog.Targets; 4 | 5 | namespace ServiceLib.Common; 6 | 7 | public class Logging 8 | { 9 | private static readonly Logger _logger1 = LogManager.GetLogger("Log1"); 10 | private static readonly Logger _logger2 = LogManager.GetLogger("Log2"); 11 | 12 | public static void Setup() 13 | { 14 | LoggingConfiguration config = new(); 15 | FileTarget fileTarget = new(); 16 | config.AddTarget("file", fileTarget); 17 | fileTarget.Layout = "${longdate}-${level:uppercase=true} ${message}"; 18 | fileTarget.FileName = Utils.GetLogPath("${shortdate}.txt"); 19 | config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, fileTarget)); 20 | LogManager.Configuration = config; 21 | } 22 | 23 | public static void LoggingEnabled(bool enable) 24 | { 25 | if (!enable) 26 | { 27 | LogManager.SuspendLogging(); 28 | } 29 | } 30 | 31 | public static void SaveLog(string strContent) 32 | { 33 | if (!LogManager.IsLoggingEnabled()) 34 | { 35 | return; 36 | } 37 | 38 | _logger1.Info(strContent); 39 | } 40 | 41 | public static void SaveLog(string strTitle, Exception ex) 42 | { 43 | if (!LogManager.IsLoggingEnabled()) 44 | { 45 | return; 46 | } 47 | 48 | _logger2.Debug($"{strTitle},{ex.Message}"); 49 | _logger2.Debug(ex.StackTrace); 50 | if (ex?.InnerException != null) 51 | { 52 | _logger2.Error(ex.InnerException); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/QRCodeHelper.cs: -------------------------------------------------------------------------------- 1 | using QRCoder; 2 | using SkiaSharp; 3 | using ZXing.SkiaSharp; 4 | 5 | namespace ServiceLib.Common; 6 | 7 | public class QRCodeHelper 8 | { 9 | public static byte[]? GenQRCode(string? url) 10 | { 11 | using QRCodeGenerator qrGenerator = new(); 12 | using var qrCodeData = qrGenerator.CreateQrCode(url ?? string.Empty, QRCodeGenerator.ECCLevel.Q); 13 | using PngByteQRCode qrCode = new(qrCodeData); 14 | return qrCode.GetGraphic(20); 15 | } 16 | 17 | public static string? ParseBarcode(string? fileName) 18 | { 19 | if (fileName == null || !File.Exists(fileName)) 20 | { 21 | return null; 22 | } 23 | 24 | try 25 | { 26 | var image = SKImage.FromEncodedData(fileName); 27 | var bitmap = SKBitmap.FromImage(image); 28 | 29 | return ReaderBarcode(bitmap); 30 | } 31 | catch 32 | { 33 | // ignored 34 | } 35 | 36 | return null; 37 | } 38 | 39 | public static string? ParseBarcode(byte[]? bytes) 40 | { 41 | try 42 | { 43 | var bitmap = SKBitmap.Decode(bytes); 44 | //using var stream = new FileStream("test2.png", FileMode.Create, FileAccess.Write); 45 | //using var image = SKImage.FromBitmap(bitmap); 46 | //using var encodedImage = image.Encode(); 47 | //encodedImage.SaveTo(stream); 48 | return ReaderBarcode(bitmap); 49 | } 50 | catch 51 | { 52 | // ignored 53 | } 54 | 55 | return null; 56 | } 57 | 58 | private static string? ReaderBarcode(SKBitmap? bitmap) 59 | { 60 | var reader = new BarcodeReader(); 61 | var result = reader.Decode(bitmap); 62 | 63 | if (result != null && result.Text.IsNotEmpty()) 64 | { 65 | return result.Text; 66 | } 67 | 68 | //FlipBitmap 69 | var result2 = reader.Decode(FlipBitmap(bitmap)); 70 | return result2?.Text; 71 | } 72 | 73 | private static SKBitmap FlipBitmap(SKBitmap bmp) 74 | { 75 | // Create a bitmap (to return) 76 | var flipped = new SKBitmap(bmp.Width, bmp.Height, bmp.Info.ColorType, bmp.Info.AlphaType); 77 | 78 | // Create a canvas to draw into the bitmap 79 | using var canvas = new SKCanvas(flipped); 80 | 81 | // Set a transform matrix which moves the bitmap to the right, 82 | // and then "scales" it by -1, which just flips the pixels 83 | // horizontally 84 | canvas.Translate(bmp.Width, 0); 85 | canvas.Scale(-1, 1); 86 | canvas.DrawBitmap(bmp, 0, 0); 87 | return flipped; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/SqliteHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using SQLite; 3 | 4 | namespace ServiceLib.Common; 5 | 6 | public sealed class SQLiteHelper 7 | { 8 | private static readonly Lazy _instance = new(() => new()); 9 | public static SQLiteHelper Instance => _instance.Value; 10 | private readonly string _connstr; 11 | private SQLiteConnection _db; 12 | private SQLiteAsyncConnection _dbAsync; 13 | private readonly string _configDB = "guiNDB.db"; 14 | 15 | public SQLiteHelper() 16 | { 17 | _connstr = Utils.GetConfigPath(_configDB); 18 | _db = new SQLiteConnection(_connstr, false); 19 | _dbAsync = new SQLiteAsyncConnection(_connstr, false); 20 | } 21 | 22 | public CreateTableResult CreateTable() 23 | { 24 | return _db.CreateTable(); 25 | } 26 | 27 | public async Task InsertAllAsync(IEnumerable models) 28 | { 29 | return await _dbAsync.InsertAllAsync(models); 30 | } 31 | 32 | public async Task InsertAsync(object model) 33 | { 34 | return await _dbAsync.InsertAsync(model); 35 | } 36 | 37 | public async Task ReplaceAsync(object model) 38 | { 39 | return await _dbAsync.InsertOrReplaceAsync(model); 40 | } 41 | 42 | public async Task UpdateAsync(object model) 43 | { 44 | return await _dbAsync.UpdateAsync(model); 45 | } 46 | 47 | public async Task UpdateAllAsync(IEnumerable models) 48 | { 49 | return await _dbAsync.UpdateAllAsync(models); 50 | } 51 | 52 | public async Task DeleteAsync(object model) 53 | { 54 | return await _dbAsync.DeleteAsync(model); 55 | } 56 | 57 | public async Task DeleteAllAsync() 58 | { 59 | return await _dbAsync.DeleteAllAsync(); 60 | } 61 | 62 | public async Task ExecuteAsync(string sql) 63 | { 64 | return await _dbAsync.ExecuteAsync(sql); 65 | } 66 | 67 | public async Task> QueryAsync(string sql) where T : new() 68 | { 69 | return await _dbAsync.QueryAsync(sql); 70 | } 71 | 72 | public AsyncTableQuery TableAsync() where T : new() 73 | { 74 | return _dbAsync.Table(); 75 | } 76 | 77 | public async Task DisposeDbConnectionAsync() 78 | { 79 | await Task.Factory.StartNew(() => 80 | { 81 | _db?.Close(); 82 | _db?.Dispose(); 83 | _db = null; 84 | 85 | _dbAsync?.GetConnection()?.Close(); 86 | _dbAsync?.GetConnection()?.Dispose(); 87 | _dbAsync = null; 88 | }); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/StringEx.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace ServiceLib.Common; 4 | 5 | public static class StringEx 6 | { 7 | public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value) 8 | { 9 | return string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value); 10 | } 11 | 12 | public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value) 13 | { 14 | return string.IsNullOrWhiteSpace(value); 15 | } 16 | 17 | public static bool IsNotEmpty([NotNullWhen(false)] this string? value) 18 | { 19 | return !string.IsNullOrEmpty(value); 20 | } 21 | 22 | public static bool BeginWithAny(this string s, IEnumerable chars) 23 | { 24 | if (s.IsNullOrEmpty()) 25 | { 26 | return false; 27 | } 28 | return chars.Contains(s.First()); 29 | } 30 | 31 | private static bool IsWhiteSpace(this string value) 32 | { 33 | return value.All(char.IsWhiteSpace); 34 | } 35 | 36 | public static IEnumerable NonWhiteSpaceLines(this TextReader reader) 37 | { 38 | while (reader.ReadLine() is { } line) 39 | { 40 | if (line.IsWhiteSpace()) 41 | { 42 | continue; 43 | } 44 | yield return line; 45 | } 46 | } 47 | 48 | public static string TrimEx(this string? value) 49 | { 50 | return value == null ? string.Empty : value.Trim(); 51 | } 52 | 53 | public static string RemovePrefix(this string value, char prefix) 54 | { 55 | return value.StartsWith(prefix) ? value[1..] : value; 56 | } 57 | 58 | public static string RemovePrefix(this string value, string prefix) 59 | { 60 | return value.StartsWith(prefix) ? value[prefix.Length..] : value; 61 | } 62 | 63 | public static string UpperFirstChar(this string value) 64 | { 65 | if (string.IsNullOrEmpty(value)) 66 | { 67 | return string.Empty; 68 | } 69 | 70 | return char.ToUpper(value.First()) + value[1..]; 71 | } 72 | 73 | public static string AppendQuotes(this string value) 74 | { 75 | return string.IsNullOrEmpty(value) ? string.Empty : $"\"{value}\""; 76 | } 77 | 78 | public static int ToInt(this string? value, int defaultValue = 0) 79 | { 80 | return int.TryParse(value, out var result) ? result : defaultValue; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/WindowsUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Text; 3 | using Microsoft.Win32; 4 | 5 | namespace ServiceLib.Common; 6 | 7 | internal static class WindowsUtils 8 | { 9 | private static readonly string _tag = "WindowsUtils"; 10 | 11 | public static string? RegReadValue(string path, string name, string def) 12 | { 13 | RegistryKey? regKey = null; 14 | try 15 | { 16 | regKey = Registry.CurrentUser.OpenSubKey(path, false); 17 | var value = regKey?.GetValue(name) as string; 18 | return value.IsNullOrEmpty() ? def : value; 19 | } 20 | catch (Exception ex) 21 | { 22 | Logging.SaveLog(_tag, ex); 23 | } 24 | finally 25 | { 26 | regKey?.Close(); 27 | } 28 | return def; 29 | } 30 | 31 | public static void RegWriteValue(string path, string name, object value) 32 | { 33 | RegistryKey? regKey = null; 34 | try 35 | { 36 | regKey = Registry.CurrentUser.CreateSubKey(path); 37 | if (value.ToString().IsNullOrEmpty()) 38 | { 39 | regKey?.DeleteValue(name, false); 40 | } 41 | else 42 | { 43 | regKey?.SetValue(name, value); 44 | } 45 | } 46 | catch (Exception ex) 47 | { 48 | Logging.SaveLog(_tag, ex); 49 | } 50 | finally 51 | { 52 | regKey?.Close(); 53 | } 54 | } 55 | 56 | public static async Task RemoveTunDevice() 57 | { 58 | try 59 | { 60 | var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun")); 61 | var guid = new Guid(sum); 62 | var pnpUtilPath = @"C:\Windows\System32\pnputil.exe"; 63 | var arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """; 64 | 65 | // Try to remove the device 66 | _ = await Utils.GetCliWrapOutput(pnpUtilPath, arg); 67 | } 68 | catch (Exception ex) 69 | { 70 | Logging.SaveLog(_tag, ex); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Common/YamlUtils.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.Core; 2 | using YamlDotNet.Serialization; 3 | using YamlDotNet.Serialization.NamingConventions; 4 | 5 | namespace ServiceLib.Common; 6 | 7 | public class YamlUtils 8 | { 9 | private static readonly string _tag = "YamlUtils"; 10 | 11 | #region YAML 12 | 13 | /// 14 | /// Deserialize 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static T FromYaml(string str) 20 | { 21 | var deserializer = new DeserializerBuilder() 22 | .WithNamingConvention(PascalCaseNamingConvention.Instance) 23 | .Build(); 24 | try 25 | { 26 | var obj = deserializer.Deserialize(str); 27 | return obj; 28 | } 29 | catch (Exception ex) 30 | { 31 | Logging.SaveLog(_tag, ex); 32 | return deserializer.Deserialize(""); 33 | } 34 | } 35 | 36 | /// 37 | /// Serialize 38 | /// 39 | /// 40 | /// 41 | public static string ToYaml(object? obj) 42 | { 43 | var result = string.Empty; 44 | if (obj == null) 45 | { 46 | return result; 47 | } 48 | var serializer = new SerializerBuilder() 49 | .WithNamingConvention(HyphenatedNamingConvention.Instance) 50 | .Build(); 51 | 52 | try 53 | { 54 | result = serializer.Serialize(obj); 55 | } 56 | catch (Exception ex) 57 | { 58 | Logging.SaveLog(_tag, ex); 59 | } 60 | return result; 61 | } 62 | 63 | public static string? PreprocessYaml(string str) 64 | { 65 | try 66 | { 67 | var mergingParser = new MergingParser(new Parser(new StringReader(str))); 68 | var obj = new DeserializerBuilder().Build().Deserialize(mergingParser); 69 | return ToYaml(obj); 70 | } 71 | catch (Exception ex) 72 | { 73 | Logging.SaveLog(_tag, ex); 74 | return null; 75 | } 76 | } 77 | 78 | #endregion YAML 79 | } 80 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EConfigType.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EConfigType 4 | { 5 | VMess = 1, 6 | Custom = 2, 7 | Shadowsocks = 3, 8 | SOCKS = 4, 9 | VLESS = 5, 10 | Trojan = 6, 11 | Hysteria2 = 7, 12 | TUIC = 8, 13 | WireGuard = 9, 14 | HTTP = 10 15 | } 16 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/ECoreType.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum ECoreType 4 | { 5 | v2fly = 1, 6 | Xray = 2, 7 | v2fly_v5 = 4, 8 | mihomo = 13, 9 | hysteria = 21, 10 | naiveproxy = 22, 11 | tuic = 23, 12 | sing_box = 24, 13 | juicity = 25, 14 | hysteria2 = 26, 15 | brook = 27, 16 | overtls = 28, 17 | v2rayN = 99 18 | } 19 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EGirdOrientation.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EGirdOrientation 4 | { 5 | Horizontal, 6 | Vertical, 7 | Tab, 8 | } 9 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EGlobalHotkey.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EGlobalHotkey 4 | { 5 | ShowForm = 0, 6 | SystemProxyClear = 1, 7 | SystemProxySet = 2, 8 | SystemProxyUnchanged = 3, 9 | SystemProxyPac = 4, 10 | } 11 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EInboundProtocol.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EInboundProtocol 4 | { 5 | socks = 0, 6 | socks2, 7 | socks3, 8 | pac, 9 | api, 10 | api2, 11 | mixed, 12 | speedtest = 21 13 | } 14 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EMove.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EMove 4 | { 5 | Top = 1, 6 | Up = 2, 7 | Down = 3, 8 | Bottom = 4, 9 | Position = 5 10 | } 11 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EMsgCommand.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EMsgCommand 4 | { 5 | ClearMsg, 6 | SendMsgView, 7 | SendSnackMsg, 8 | RefreshProfiles, 9 | AppExit 10 | } 11 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EMultipleLoad.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EMultipleLoad 4 | { 5 | Random, 6 | RoundRobin, 7 | LeastPing, 8 | LeastLoad 9 | } 10 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EPresetType.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EPresetType 4 | { 5 | Default = 0, 6 | Russia = 1, 7 | Iran = 2, 8 | } 9 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/ERuleMode.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum ERuleMode 4 | { 5 | Rule = 0, 6 | Global = 1, 7 | Direct = 2, 8 | Unchanged = 3 9 | } 10 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EServerColName.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EServerColName 4 | { 5 | Def = 0, 6 | ConfigType, 7 | Remarks, 8 | Address, 9 | Port, 10 | Network, 11 | StreamSecurity, 12 | SubRemarks, 13 | DelayVal, 14 | SpeedVal, 15 | 16 | TodayDown, 17 | TodayUp, 18 | TotalDown, 19 | TotalUp 20 | } 21 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/ESpeedActionType.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum ESpeedActionType 4 | { 5 | Tcping, 6 | Realping, 7 | Speedtest, 8 | Mixedtest 9 | } 10 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/ESysProxyType.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum ESysProxyType 4 | { 5 | ForcedClear = 0, 6 | ForcedChange = 1, 7 | Unchanged = 2, 8 | Pac = 3 9 | } 10 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/ETheme.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum ETheme 4 | { 5 | FollowSystem, 6 | Dark, 7 | Light, 8 | Aquatic, 9 | Desert, 10 | Dusk, 11 | NightSky 12 | } 13 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/ETransport.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum ETransport 4 | { 5 | tcp, 6 | kcp, 7 | ws, 8 | httpupgrade, 9 | xhttp, 10 | h2, 11 | http, 12 | quic, 13 | grpc 14 | } 15 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Enums/EViewAction.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Enums; 2 | 3 | public enum EViewAction 4 | { 5 | CloseWindow, 6 | ShowYesNo, 7 | SaveFileDialog, 8 | AddBatchRoutingRulesYesNo, 9 | AdjustMainLvColWidth, 10 | SetClipboardData, 11 | AddServerViaClipboard, 12 | ImportRulesFromClipboard, 13 | ProfilesFocus, 14 | ShareSub, 15 | ShareServer, 16 | ShowHideWindow, 17 | ScanScreenTask, 18 | ScanImageTask, 19 | Shutdown, 20 | BrowseServer, 21 | ImportRulesFromFile, 22 | InitSettingFont, 23 | PasswordInput, 24 | SubEditWindow, 25 | RoutingRuleSettingWindow, 26 | RoutingRuleDetailsWindow, 27 | AddServerWindow, 28 | AddServer2Window, 29 | DNSSettingWindow, 30 | RoutingSettingWindow, 31 | OptionSettingWindow, 32 | GlobalHotkeySettingWindow, 33 | SubSettingWindow, 34 | DispatcherSpeedTest, 35 | DispatcherRefreshConnections, 36 | DispatcherRefreshProxyGroups, 37 | DispatcherProxiesDelayTest, 38 | DispatcherStatistics, 39 | DispatcherServerAvailability, 40 | DispatcherReload, 41 | DispatcherRefreshServersBiz, 42 | DispatcherRefreshIcon, 43 | DispatcherCheckUpdate, 44 | DispatcherCheckUpdateFinished, 45 | DispatcherShowMsg, 46 | } 47 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using ServiceLib.Base; 2 | global using ServiceLib.Common; 3 | global using ServiceLib.Enums; 4 | global using ServiceLib.Handler; 5 | global using ServiceLib.Handler.Fmt; 6 | global using ServiceLib.Services; 7 | global using ServiceLib.Services.Statistics; 8 | global using ServiceLib.Services.CoreConfig; 9 | global using ServiceLib.Models; 10 | global using ServiceLib.Resx; 11 | global using ServiceLib.Handler.SysProxy; -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/ConnectionHandler.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler; 2 | 3 | public class ConnectionHandler 4 | { 5 | private static readonly Lazy _instance = new(() => new()); 6 | public static ConnectionHandler Instance => _instance.Value; 7 | 8 | public async Task RunAvailabilityCheck() 9 | { 10 | var downloadHandle = new DownloadService(); 11 | var time = await downloadHandle.RunAvailabilityCheck(null); 12 | var ip = time > 0 ? await GetIPInfo(downloadHandle) ?? Global.None : Global.None; 13 | 14 | return string.Format(ResUI.TestMeOutput, time, ip); 15 | } 16 | 17 | private async Task GetIPInfo(DownloadService downloadHandle) 18 | { 19 | var url = AppHandler.Instance.Config.SpeedTestItem.IPAPIUrl; 20 | if (url.IsNullOrEmpty()) 21 | { 22 | return null; 23 | } 24 | 25 | var result = await downloadHandle.TryDownloadString(url, true, ""); 26 | if (result == null) 27 | { 28 | return null; 29 | } 30 | 31 | var ipInfo = JsonUtils.Deserialize(result); 32 | if (ipInfo == null) 33 | { 34 | return null; 35 | } 36 | 37 | var ip = ipInfo.ip ?? ipInfo.clientIp ?? ipInfo.ip_addr ?? ipInfo.query; 38 | var country = ipInfo.country_code ?? ipInfo.country ?? ipInfo.countryCode ?? ipInfo.location?.country_code; 39 | 40 | return $"({country ?? "unknown"}) {ip}"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/ClashFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class ClashFmt : BaseFmt 4 | { 5 | public static ProfileItem? ResolveFull(string strData, string? subRemarks) 6 | { 7 | if (Contains(strData, "port", "socks-port", "proxies")) 8 | { 9 | var fileName = WriteAllText(strData, "yaml"); 10 | 11 | var profileItem = new ProfileItem 12 | { 13 | CoreType = ECoreType.mihomo, 14 | Address = fileName, 15 | Remarks = subRemarks ?? "clash_custom" 16 | }; 17 | return profileItem; 18 | } 19 | 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/NaiveproxyFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class NaiveproxyFmt : BaseFmt 4 | { 5 | public static ProfileItem? ResolveFull(string strData, string? subRemarks) 6 | { 7 | if (Contains(strData, "listen", "proxy", "", "")) 8 | { 9 | var fileName = WriteAllText(strData); 10 | 11 | var profileItem = new ProfileItem 12 | { 13 | CoreType = ECoreType.naiveproxy, 14 | Address = fileName, 15 | Remarks = subRemarks ?? "naiveproxy_custom" 16 | }; 17 | return profileItem; 18 | } 19 | 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/SingboxFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class SingboxFmt : BaseFmt 4 | { 5 | public static List? ResolveFullArray(string strData, string? subRemarks) 6 | { 7 | var configObjects = JsonUtils.Deserialize(strData); 8 | if (configObjects is not { Length: > 0 }) 9 | { 10 | return null; 11 | } 12 | 13 | List lstResult = []; 14 | foreach (var configObject in configObjects) 15 | { 16 | var objectString = JsonUtils.Serialize(configObject); 17 | var profileIt = ResolveFull(objectString, subRemarks); 18 | if (profileIt != null) 19 | { 20 | lstResult.Add(profileIt); 21 | } 22 | } 23 | return lstResult; 24 | } 25 | 26 | public static ProfileItem? ResolveFull(string strData, string? subRemarks) 27 | { 28 | var config = JsonUtils.ParseJson(strData); 29 | if (config?["inbounds"] == null 30 | || config["outbounds"] == null 31 | || config["route"] == null 32 | || config["dns"] == null) 33 | { 34 | return null; 35 | } 36 | 37 | var fileName = WriteAllText(strData); 38 | var profileItem = new ProfileItem 39 | { 40 | CoreType = ECoreType.sing_box, 41 | Address = fileName, 42 | Remarks = subRemarks ?? "singbox_custom" 43 | }; 44 | 45 | return profileItem; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/TrojanFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class TrojanFmt : BaseFmt 4 | { 5 | public static ProfileItem? Resolve(string str, out string msg) 6 | { 7 | msg = ResUI.ConfigurationFormatIncorrect; 8 | 9 | ProfileItem item = new() 10 | { 11 | ConfigType = EConfigType.Trojan 12 | }; 13 | 14 | var url = Utils.TryUri(str); 15 | if (url == null) 16 | { 17 | return null; 18 | } 19 | 20 | item.Address = url.IdnHost; 21 | item.Port = url.Port; 22 | item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); 23 | item.Id = Utils.UrlDecode(url.UserInfo); 24 | 25 | var query = Utils.ParseQueryString(url.Query); 26 | _ = ResolveStdTransport(query, ref item); 27 | 28 | return item; 29 | } 30 | 31 | public static string? ToUri(ProfileItem? item) 32 | { 33 | if (item == null) 34 | { 35 | return null; 36 | } 37 | var remark = string.Empty; 38 | if (item.Remarks.IsNotEmpty()) 39 | { 40 | remark = "#" + Utils.UrlEncode(item.Remarks); 41 | } 42 | var dicQuery = new Dictionary(); 43 | _ = GetStdTransport(item, null, ref dicQuery); 44 | 45 | return ToUri(EConfigType.Trojan, item.Address, item.Port, item.Id, dicQuery, remark); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/TuicFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class TuicFmt : BaseFmt 4 | { 5 | public static ProfileItem? Resolve(string str, out string msg) 6 | { 7 | msg = ResUI.ConfigurationFormatIncorrect; 8 | 9 | ProfileItem item = new() 10 | { 11 | ConfigType = EConfigType.TUIC 12 | }; 13 | 14 | var url = Utils.TryUri(str); 15 | if (url == null) 16 | { 17 | return null; 18 | } 19 | 20 | item.Address = url.IdnHost; 21 | item.Port = url.Port; 22 | item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); 23 | var rawUserInfo = Utils.UrlDecode(url.UserInfo); 24 | var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); 25 | if (userInfoParts.Length == 2) 26 | { 27 | item.Id = userInfoParts.First(); 28 | item.Security = userInfoParts.Last(); 29 | } 30 | 31 | var query = Utils.ParseQueryString(url.Query); 32 | ResolveStdTransport(query, ref item); 33 | item.HeaderType = query["congestion_control"] ?? ""; 34 | 35 | return item; 36 | } 37 | 38 | public static string? ToUri(ProfileItem? item) 39 | { 40 | if (item == null) 41 | { 42 | return null; 43 | } 44 | 45 | var remark = string.Empty; 46 | if (item.Remarks.IsNotEmpty()) 47 | { 48 | remark = "#" + Utils.UrlEncode(item.Remarks); 49 | } 50 | var dicQuery = new Dictionary(); 51 | if (item.Sni.IsNotEmpty()) 52 | { 53 | dicQuery.Add("sni", item.Sni); 54 | } 55 | if (item.Alpn.IsNotEmpty()) 56 | { 57 | dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn)); 58 | } 59 | dicQuery.Add("congestion_control", item.HeaderType); 60 | 61 | return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Id}:{item.Security}", dicQuery, remark); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/V2rayFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class V2rayFmt : BaseFmt 4 | { 5 | public static List? ResolveFullArray(string strData, string? subRemarks) 6 | { 7 | var configObjects = JsonUtils.Deserialize(strData); 8 | if (configObjects is not { Length: > 0 }) 9 | { 10 | return null; 11 | } 12 | 13 | List lstResult = []; 14 | foreach (var configObject in configObjects) 15 | { 16 | var objectString = JsonUtils.Serialize(configObject); 17 | var profileIt = ResolveFull(objectString, subRemarks); 18 | if (profileIt != null) 19 | { 20 | lstResult.Add(profileIt); 21 | } 22 | } 23 | 24 | return lstResult; 25 | } 26 | 27 | public static ProfileItem? ResolveFull(string strData, string? subRemarks) 28 | { 29 | var config = JsonUtils.ParseJson(strData); 30 | if (config?["inbounds"] == null 31 | || config["outbounds"] == null 32 | || config["routing"] == null) 33 | { 34 | return null; 35 | } 36 | 37 | var fileName = WriteAllText(strData); 38 | 39 | var profileItem = new ProfileItem 40 | { 41 | CoreType = ECoreType.Xray, 42 | Address = fileName, 43 | Remarks = config?["remarks"]?.ToString() ?? subRemarks ?? "v2ray_custom" 44 | }; 45 | 46 | return profileItem; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/VLESSFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class VLESSFmt : BaseFmt 4 | { 5 | public static ProfileItem? Resolve(string str, out string msg) 6 | { 7 | msg = ResUI.ConfigurationFormatIncorrect; 8 | 9 | ProfileItem item = new() 10 | { 11 | ConfigType = EConfigType.VLESS, 12 | Security = Global.None 13 | }; 14 | 15 | var url = Utils.TryUri(str); 16 | if (url == null) 17 | { 18 | return null; 19 | } 20 | 21 | item.Address = url.IdnHost; 22 | item.Port = url.Port; 23 | item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); 24 | item.Id = Utils.UrlDecode(url.UserInfo); 25 | 26 | var query = Utils.ParseQueryString(url.Query); 27 | item.Security = query["encryption"] ?? Global.None; 28 | item.StreamSecurity = query["security"] ?? ""; 29 | _ = ResolveStdTransport(query, ref item); 30 | 31 | return item; 32 | } 33 | 34 | public static string? ToUri(ProfileItem? item) 35 | { 36 | if (item == null) 37 | { 38 | return null; 39 | } 40 | 41 | var remark = string.Empty; 42 | if (item.Remarks.IsNotEmpty()) 43 | { 44 | remark = "#" + Utils.UrlEncode(item.Remarks); 45 | } 46 | var dicQuery = new Dictionary(); 47 | if (item.Security.IsNotEmpty()) 48 | { 49 | dicQuery.Add("encryption", item.Security); 50 | } 51 | else 52 | { 53 | dicQuery.Add("encryption", Global.None); 54 | } 55 | _ = GetStdTransport(item, Global.None, ref dicQuery); 56 | 57 | return ToUri(EConfigType.VLESS, item.Address, item.Port, item.Id, dicQuery, remark); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.Fmt; 2 | 3 | public class WireguardFmt : BaseFmt 4 | { 5 | public static ProfileItem? Resolve(string str, out string msg) 6 | { 7 | msg = ResUI.ConfigurationFormatIncorrect; 8 | 9 | ProfileItem item = new() 10 | { 11 | ConfigType = EConfigType.WireGuard 12 | }; 13 | 14 | var url = Utils.TryUri(str); 15 | if (url == null) 16 | { 17 | return null; 18 | } 19 | 20 | item.Address = url.IdnHost; 21 | item.Port = url.Port; 22 | item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); 23 | item.Id = Utils.UrlDecode(url.UserInfo); 24 | 25 | var query = Utils.ParseQueryString(url.Query); 26 | 27 | item.PublicKey = Utils.UrlDecode(query["publickey"] ?? ""); 28 | item.Path = Utils.UrlDecode(query["reserved"] ?? ""); 29 | item.RequestHost = Utils.UrlDecode(query["address"] ?? ""); 30 | item.ShortId = Utils.UrlDecode(query["mtu"] ?? ""); 31 | 32 | return item; 33 | } 34 | 35 | public static string? ToUri(ProfileItem? item) 36 | { 37 | if (item == null) 38 | { 39 | return null; 40 | } 41 | 42 | var remark = string.Empty; 43 | if (item.Remarks.IsNotEmpty()) 44 | { 45 | remark = "#" + Utils.UrlEncode(item.Remarks); 46 | } 47 | 48 | var dicQuery = new Dictionary(); 49 | if (item.PublicKey.IsNotEmpty()) 50 | { 51 | dicQuery.Add("publickey", Utils.UrlEncode(item.PublicKey)); 52 | } 53 | if (item.Path.IsNotEmpty()) 54 | { 55 | dicQuery.Add("reserved", Utils.UrlEncode(item.Path)); 56 | } 57 | if (item.RequestHost.IsNotEmpty()) 58 | { 59 | dicQuery.Add("address", Utils.UrlEncode(item.RequestHost)); 60 | } 61 | if (item.ShortId.IsNotEmpty()) 62 | { 63 | dicQuery.Add("mtu", Utils.UrlEncode(item.ShortId)); 64 | } 65 | return ToUri(EConfigType.WireGuard, item.Address, item.Port, item.Id, dicQuery, remark); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/NoticeHandler.cs: -------------------------------------------------------------------------------- 1 | using ReactiveUI; 2 | 3 | namespace ServiceLib.Handler; 4 | 5 | public class NoticeHandler 6 | { 7 | private static readonly Lazy _instance = new(() => new()); 8 | public static NoticeHandler Instance => _instance.Value; 9 | 10 | public void Enqueue(string? content) 11 | { 12 | if (content.IsNullOrEmpty()) 13 | { 14 | return; 15 | } 16 | MessageBus.Current.SendMessage(content, EMsgCommand.SendSnackMsg.ToString()); 17 | } 18 | 19 | public void SendMessage(string? content) 20 | { 21 | if (content.IsNullOrEmpty()) 22 | { 23 | return; 24 | } 25 | MessageBus.Current.SendMessage(content, EMsgCommand.SendMsgView.ToString()); 26 | } 27 | 28 | public void SendMessageEx(string? content) 29 | { 30 | if (content.IsNullOrEmpty()) 31 | { 32 | return; 33 | } 34 | content = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss} {content}"; 35 | SendMessage(content); 36 | } 37 | 38 | public void SendMessageAndEnqueue(string? msg) 39 | { 40 | Enqueue(msg); 41 | SendMessage(msg); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.SysProxy; 2 | 3 | public class ProxySettingLinux 4 | { 5 | private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh"; 6 | 7 | public static async Task SetProxy(string host, int port, string exceptions) 8 | { 9 | List args = ["manual", host, port.ToString(), exceptions]; 10 | await ExecCmd(args); 11 | } 12 | 13 | public static async Task UnsetProxy() 14 | { 15 | List args = ["none"]; 16 | await ExecCmd(args); 17 | } 18 | 19 | private static async Task ExecCmd(List args) 20 | { 21 | var fileName = Utils.GetBinConfigPath(_proxySetFileName); 22 | if (!File.Exists(fileName)) 23 | { 24 | var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName); 25 | await File.AppendAllTextAsync(fileName, contents); 26 | 27 | await Utils.SetLinuxChmod(fileName); 28 | } 29 | 30 | await Utils.GetCliWrapOutput(fileName, args); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Handler.SysProxy; 2 | 3 | public class ProxySettingOSX 4 | { 5 | private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh"; 6 | 7 | public static async Task SetProxy(string host, int port, string exceptions) 8 | { 9 | List args = ["set", host, port.ToString()]; 10 | if (exceptions.IsNotEmpty()) 11 | { 12 | args.AddRange(exceptions.Split(',')); 13 | } 14 | 15 | await ExecCmd(args); 16 | } 17 | 18 | public static async Task UnsetProxy() 19 | { 20 | List args = ["clear"]; 21 | await ExecCmd(args); 22 | } 23 | 24 | private static async Task ExecCmd(List args) 25 | { 26 | var fileName = Utils.GetBinConfigPath(_proxySetFileName); 27 | if (!File.Exists(fileName)) 28 | { 29 | var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName); 30 | await File.AppendAllTextAsync(fileName, contents); 31 | 32 | await Utils.SetLinuxChmod(fileName); 33 | } 34 | 35 | await Utils.GetCliWrapOutput(fileName, args); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/CheckUpdateModel.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class CheckUpdateModel 4 | { 5 | public bool? IsSelected { get; set; } 6 | public string? CoreType { get; set; } 7 | public string? Remarks { get; set; } 8 | public string? FileName { get; set; } 9 | public bool? IsFinished { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ClashConnectionModel.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class ClashConnectionModel 4 | { 5 | public string? Id { get; set; } 6 | public string? Network { get; set; } 7 | public string? Type { get; set; } 8 | public string? Host { get; set; } 9 | public ulong Upload { get; set; } 10 | public ulong Download { get; set; } 11 | public string? UploadTraffic { get; set; } 12 | public string? DownloadTraffic { get; set; } 13 | public double Time { get; set; } 14 | public string? Elapsed { get; set; } 15 | public string? Chain { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ClashConnections.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class ClashConnections 4 | { 5 | public ulong downloadTotal { get; set; } 6 | public ulong uploadTotal { get; set; } 7 | public List? connections { get; set; } 8 | } 9 | 10 | public class ConnectionItem 11 | { 12 | public string? id { get; set; } 13 | public MetadataItem? metadata { get; set; } 14 | public ulong upload { get; set; } 15 | public ulong download { get; set; } 16 | public DateTime start { get; set; } 17 | public List? chains { get; set; } 18 | public string? rule { get; set; } 19 | public string? rulePayload { get; set; } 20 | } 21 | 22 | public class MetadataItem 23 | { 24 | public string? network { get; set; } 25 | public string? type { get; set; } 26 | public string? sourceIP { get; set; } 27 | public string? destinationIP { get; set; } 28 | public string? sourcePort { get; set; } 29 | public string? destinationPort { get; set; } 30 | public string? host { get; set; } 31 | public string? nsMode { get; set; } 32 | public object? uid { get; set; } 33 | public string? process { get; set; } 34 | public string? processPath { get; set; } 35 | public string? remoteDestination { get; set; } 36 | } 37 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ClashProviders.cs: -------------------------------------------------------------------------------- 1 | using static ServiceLib.Models.ClashProxies; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | public class ClashProviders 6 | { 7 | public Dictionary? providers { get; set; } 8 | 9 | public class ProvidersItem 10 | { 11 | public string? name { get; set; } 12 | public List? proxies { get; set; } 13 | public string? type { get; set; } 14 | public string? vehicleType { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ClashProxies.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class ClashProxies 4 | { 5 | public Dictionary? proxies { get; set; } 6 | 7 | public class ProxiesItem 8 | { 9 | public List? all { get; set; } 10 | public List? history { get; set; } 11 | public string? name { get; set; } 12 | public string? type { get; set; } 13 | public bool udp { get; set; } 14 | public string? now { get; set; } 15 | public int delay { get; set; } 16 | } 17 | 18 | public class HistoryItem 19 | { 20 | public string? time { get; set; } 21 | public int delay { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ClashProxyModel.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class ClashProxyModel 5 | { 6 | public string? Name { get; set; } 7 | 8 | public string? Type { get; set; } 9 | 10 | public string? Now { get; set; } 11 | 12 | public int Delay { get; set; } 13 | 14 | public string? DelayName { get; set; } 15 | 16 | public bool IsActive { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/CmdItem.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class CmdItem 4 | { 5 | public string? Cmd { get; set; } 6 | public List? Arguments { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ComboItem.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class ComboItem 4 | { 5 | public string? ID 6 | { 7 | get; set; 8 | } 9 | 10 | public string? Text 11 | { 12 | get; set; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/Config.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class Config 5 | { 6 | #region property 7 | 8 | public string IndexId { get; set; } 9 | public string SubIndexId { get; set; } 10 | 11 | public ECoreType RunningCoreType { get; set; } 12 | 13 | public bool IsRunningCore(ECoreType type) 14 | { 15 | switch (type) 16 | { 17 | case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5: 18 | case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo: 19 | return true; 20 | 21 | default: 22 | return false; 23 | } 24 | } 25 | 26 | #endregion property 27 | 28 | #region other entities 29 | 30 | public CoreBasicItem CoreBasicItem { get; set; } 31 | public TunModeItem TunModeItem { get; set; } 32 | public KcpItem KcpItem { get; set; } 33 | public GrpcItem GrpcItem { get; set; } 34 | public RoutingBasicItem RoutingBasicItem { get; set; } 35 | public GUIItem GuiItem { get; set; } 36 | public MsgUIItem MsgUIItem { get; set; } 37 | public UIItem UiItem { get; set; } 38 | public ConstItem ConstItem { get; set; } 39 | public SpeedTestItem SpeedTestItem { get; set; } 40 | public Mux4RayItem Mux4RayItem { get; set; } 41 | public Mux4SboxItem Mux4SboxItem { get; set; } 42 | public HysteriaItem HysteriaItem { get; set; } 43 | public ClashUIItem ClashUIItem { get; set; } 44 | public SystemProxyItem SystemProxyItem { get; set; } 45 | public WebDavItem WebDavItem { get; set; } 46 | public CheckUpdateItem CheckUpdateItem { get; set; } 47 | public Fragment4RayItem? Fragment4RayItem { get; set; } 48 | public List Inbound { get; set; } 49 | public List GlobalHotkeys { get; set; } 50 | public List CoreTypeItem { get; set; } 51 | 52 | #endregion other entities 53 | } 54 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/CoreInfo.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class CoreInfo 5 | { 6 | public ECoreType CoreType { get; set; } 7 | public List? CoreExes { get; set; } 8 | public string? Arguments { get; set; } 9 | public string? Url { get; set; } 10 | public string? ReleaseApiUrl { get; set; } 11 | public string? DownloadUrlWin64 { get; set; } 12 | public string? DownloadUrlWinArm64 { get; set; } 13 | public string? DownloadUrlLinux64 { get; set; } 14 | public string? DownloadUrlLinuxArm64 { get; set; } 15 | public string? DownloadUrlOSX64 { get; set; } 16 | public string? DownloadUrlOSXArm64 { get; set; } 17 | public string? Match { get; set; } 18 | public string? VersionArg { get; set; } 19 | public bool AbsolutePath { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/DNSItem.cs: -------------------------------------------------------------------------------- 1 | using SQLite; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | [Serializable] 6 | public class DNSItem 7 | { 8 | [PrimaryKey] 9 | public string Id { get; set; } 10 | 11 | public string Remarks { get; set; } 12 | public bool Enabled { get; set; } = true; 13 | public ECoreType CoreType { get; set; } 14 | public bool UseSystemHosts { get; set; } 15 | public string? NormalDNS { get; set; } 16 | public string? TunDNS { get; set; } 17 | public string? DomainStrategy4Freedom { get; set; } 18 | public string? DomainDNSAddress { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/GitHubRelease.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | public class GitHubReleaseAsset 6 | { 7 | [JsonPropertyName("url")] public string? Url { get; set; } 8 | 9 | [JsonPropertyName("id")] public int Id { get; set; } 10 | 11 | [JsonPropertyName("node_id")] public string? NodeId { get; set; } 12 | 13 | [JsonPropertyName("name")] public string? Name { get; set; } 14 | 15 | [JsonPropertyName("label")] public object Label { get; set; } 16 | 17 | [JsonPropertyName("content_type")] public string? ContentType { get; set; } 18 | 19 | [JsonPropertyName("state")] public string? State { get; set; } 20 | 21 | [JsonPropertyName("size")] public int Size { get; set; } 22 | 23 | [JsonPropertyName("download_count")] public int DownloadCount { get; set; } 24 | 25 | [JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; } 26 | 27 | [JsonPropertyName("updated_at")] public DateTime UpdatedAt { get; set; } 28 | 29 | [JsonPropertyName("browser_download_url")] public string? BrowserDownloadUrl { get; set; } 30 | } 31 | 32 | public class GitHubRelease 33 | { 34 | [JsonPropertyName("url")] public string? Url { get; set; } 35 | 36 | [JsonPropertyName("assets_url")] public string? AssetsUrl { get; set; } 37 | 38 | [JsonPropertyName("upload_url")] public string? UploadUrl { get; set; } 39 | 40 | [JsonPropertyName("html_url")] public string? HtmlUrl { get; set; } 41 | 42 | [JsonPropertyName("id")] public int Id { get; set; } 43 | 44 | [JsonPropertyName("node_id")] public string? NodeId { get; set; } 45 | 46 | [JsonPropertyName("tag_name")] public string? TagName { get; set; } 47 | 48 | [JsonPropertyName("target_commitish")] public string? TargetCommitish { get; set; } 49 | 50 | [JsonPropertyName("name")] public string? Name { get; set; } 51 | 52 | [JsonPropertyName("draft")] public bool Draft { get; set; } 53 | 54 | [JsonPropertyName("prerelease")] public bool Prerelease { get; set; } 55 | 56 | [JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; } 57 | 58 | [JsonPropertyName("published_at")] public DateTime PublishedAt { get; set; } 59 | 60 | [JsonPropertyName("assets")] public List Assets { get; set; } 61 | 62 | [JsonPropertyName("tarball_url")] public string? TarballUrl { get; set; } 63 | 64 | [JsonPropertyName("zipball_url")] public string? ZipballUrl { get; set; } 65 | 66 | [JsonPropertyName("body")] public string? Body { get; set; } 67 | } 68 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/IPAPIInfo.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | internal class IPAPIInfo 4 | { 5 | public string? ip { get; set; } 6 | public string? clientIp { get; set; } 7 | public string? ip_addr { get; set; } 8 | public string? query { get; set; } 9 | public string? country { get; set; } 10 | public string? country_name { get; set; } 11 | public string? country_code { get; set; } 12 | public string? countryCode { get; set; } 13 | public LocationInfo? location { get; set; } 14 | } 15 | 16 | public class LocationInfo 17 | { 18 | public string? country_code { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ProfileExItem.cs: -------------------------------------------------------------------------------- 1 | using SQLite; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | [Serializable] 6 | public class ProfileExItem 7 | { 8 | [PrimaryKey] 9 | public string IndexId { get; set; } 10 | 11 | public int Delay { get; set; } 12 | public decimal Speed { get; set; } 13 | public int Sort { get; set; } 14 | public string? Message { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ProfileItem.cs: -------------------------------------------------------------------------------- 1 | using SQLite; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | [Serializable] 6 | public class ProfileItem 7 | { 8 | public ProfileItem() 9 | { 10 | IndexId = string.Empty; 11 | ConfigType = EConfigType.VMess; 12 | ConfigVersion = 2; 13 | Address = string.Empty; 14 | Port = 0; 15 | Id = string.Empty; 16 | AlterId = 0; 17 | Security = string.Empty; 18 | Network = string.Empty; 19 | Remarks = string.Empty; 20 | HeaderType = string.Empty; 21 | RequestHost = string.Empty; 22 | Path = string.Empty; 23 | StreamSecurity = string.Empty; 24 | AllowInsecure = string.Empty; 25 | Subid = string.Empty; 26 | Flow = string.Empty; 27 | } 28 | 29 | #region function 30 | 31 | public string GetSummary() 32 | { 33 | var summary = $"[{(ConfigType).ToString()}] "; 34 | var arrAddr = Address.Split('.'); 35 | var addr = arrAddr.Length switch 36 | { 37 | > 2 => $"{arrAddr.First()}***{arrAddr.Last()}", 38 | > 1 => $"***{arrAddr.Last()}", 39 | _ => Address 40 | }; 41 | summary += ConfigType switch 42 | { 43 | EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}", 44 | _ => $"{Remarks}({addr}:{Port})" 45 | }; 46 | return summary; 47 | } 48 | 49 | public List? GetAlpn() 50 | { 51 | return Alpn.IsNullOrEmpty() ? null : Utils.String2List(Alpn); 52 | } 53 | 54 | public string GetNetwork() 55 | { 56 | if (Network.IsNullOrEmpty() || !Global.Networks.Contains(Network)) 57 | { 58 | return Global.DefaultNetwork; 59 | } 60 | return Network.TrimEx(); 61 | } 62 | 63 | #endregion function 64 | 65 | [PrimaryKey] 66 | public string IndexId { get; set; } 67 | 68 | public EConfigType ConfigType { get; set; } 69 | public int ConfigVersion { get; set; } 70 | public string Address { get; set; } 71 | public int Port { get; set; } 72 | public string Ports { get; set; } 73 | public string Id { get; set; } 74 | public int AlterId { get; set; } 75 | public string Security { get; set; } 76 | public string Network { get; set; } 77 | public string Remarks { get; set; } 78 | public string HeaderType { get; set; } 79 | public string RequestHost { get; set; } 80 | public string Path { get; set; } 81 | public string StreamSecurity { get; set; } 82 | public string AllowInsecure { get; set; } 83 | public string Subid { get; set; } 84 | public bool IsSub { get; set; } = true; 85 | public string Flow { get; set; } 86 | public string Sni { get; set; } 87 | public string Alpn { get; set; } = string.Empty; 88 | public ECoreType? CoreType { get; set; } 89 | public int? PreSocksPort { get; set; } 90 | public string Fingerprint { get; set; } 91 | public bool DisplayLog { get; set; } = true; 92 | public string PublicKey { get; set; } 93 | public string ShortId { get; set; } 94 | public string SpiderX { get; set; } 95 | public string Extra { get; set; } 96 | } 97 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ProfileItemModel.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class ProfileItemModel : ProfileItem 5 | { 6 | public bool IsActive { get; set; } 7 | public string SubRemarks { get; set; } 8 | public int Delay { get; set; } 9 | public decimal Speed { get; set; } 10 | public int Sort { get; set; } 11 | public string DelayVal { get; set; } 12 | public string SpeedVal { get; set; } 13 | public string TodayUp { get; set; } 14 | public string TodayDown { get; set; } 15 | public string TotalUp { get; set; } 16 | public string TotalDown { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/RetResult.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class RetResult 4 | { 5 | public bool Success { get; set; } 6 | public string? Msg { get; set; } 7 | public object? Data { get; set; } 8 | 9 | public RetResult(bool success = false) 10 | { 11 | Success = success; 12 | } 13 | 14 | public RetResult(bool success, string? msg) 15 | { 16 | Success = success; 17 | Msg = msg; 18 | } 19 | 20 | public RetResult(bool success, string? msg, object? data) 21 | { 22 | Success = success; 23 | Msg = msg; 24 | Data = data; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/RoutingItem.cs: -------------------------------------------------------------------------------- 1 | using SQLite; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | [Serializable] 6 | public class RoutingItem 7 | { 8 | [PrimaryKey] 9 | public string Id { get; set; } 10 | 11 | public string Remarks { get; set; } 12 | public string Url { get; set; } 13 | public string RuleSet { get; set; } 14 | public int RuleNum { get; set; } 15 | public bool Enabled { get; set; } = true; 16 | public bool Locked { get; set; } 17 | public string CustomIcon { get; set; } 18 | public string CustomRulesetPath4Singbox { get; set; } 19 | public string DomainStrategy { get; set; } 20 | public string DomainStrategy4Singbox { get; set; } 21 | public int Sort { get; set; } 22 | } 23 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/RoutingItemModel.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class RoutingItemModel : RoutingItem 5 | { 6 | public bool IsActive { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/RoutingTemplate.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class RoutingTemplate 5 | { 6 | public string Version { get; set; } 7 | public RoutingItem[] RoutingItems { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/RulesItem.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class RulesItem 5 | { 6 | public string Id { get; set; } 7 | public string? Type { get; set; } 8 | public string? Port { get; set; } 9 | public string? Network { get; set; } 10 | public List? InboundTag { get; set; } 11 | public string? OutboundTag { get; set; } 12 | public List? Ip { get; set; } 13 | public List? Domain { get; set; } 14 | public List? Protocol { get; set; } 15 | public List? Process { get; set; } 16 | public bool Enabled { get; set; } = true; 17 | public string? Remarks { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/RulesItemModel.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class RulesItemModel : RulesItem 5 | { 6 | public string InboundTags { get; set; } 7 | public string Ips { get; set; } 8 | public string Domains { get; set; } 9 | public string Protocols { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ServerSpeedItem.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class ServerSpeedItem : ServerStatItem 5 | { 6 | public long ProxyUp { get; set; } 7 | 8 | public long ProxyDown { get; set; } 9 | 10 | public long DirectUp { get; set; } 11 | 12 | public long DirectDown { get; set; } 13 | } 14 | 15 | [Serializable] 16 | public class TrafficItem 17 | { 18 | public ulong Up { get; set; } 19 | 20 | public ulong Down { get; set; } 21 | } 22 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ServerStatItem.cs: -------------------------------------------------------------------------------- 1 | using SQLite; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | [Serializable] 6 | public class ServerStatItem 7 | { 8 | [PrimaryKey] 9 | public string IndexId { get; set; } 10 | 11 | public long TotalUp { get; set; } 12 | 13 | public long TotalDown { get; set; } 14 | 15 | public long TodayUp { get; set; } 16 | 17 | public long TodayDown { get; set; } 18 | 19 | public long DateNow { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/ServerTestItem.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class ServerTestItem 5 | { 6 | public string? IndexId { get; set; } 7 | public string? Address { get; set; } 8 | public int Port { get; set; } 9 | public EConfigType ConfigType { get; set; } 10 | public bool AllowTest { get; set; } 11 | public int QueueNum { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/SpeedTestResult.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | [Serializable] 4 | public class SpeedTestResult 5 | { 6 | public string? IndexId { get; set; } 7 | 8 | public string? Delay { get; set; } 9 | 10 | public string? Speed { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/SsSIP008.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class SsSIP008 4 | { 5 | public List? servers { get; set; } 6 | } 7 | 8 | [Serializable] 9 | public class SsServer 10 | { 11 | public string? remarks { get; set; } 12 | public string? server { get; set; } 13 | public string? server_port { get; set; } 14 | public string? method { get; set; } 15 | public string? password { get; set; } 16 | public string? plugin { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/SubItem.cs: -------------------------------------------------------------------------------- 1 | using SQLite; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | [Serializable] 6 | public class SubItem 7 | { 8 | [PrimaryKey] 9 | public string Id { get; set; } 10 | 11 | public string Remarks { get; set; } 12 | 13 | public string Url { get; set; } 14 | 15 | public string MoreUrl { get; set; } 16 | 17 | public bool Enabled { get; set; } = true; 18 | 19 | public string UserAgent { get; set; } = string.Empty; 20 | 21 | public int Sort { get; set; } 22 | 23 | public string? Filter { get; set; } 24 | 25 | public int AutoUpdateInterval { get; set; } 26 | 27 | public long UpdateTime { get; set; } 28 | 29 | public string? ConvertTarget { get; set; } 30 | 31 | public string? PrevProfile { get; set; } 32 | 33 | public string? NextProfile { get; set; } 34 | 35 | public int? PreSocksPort { get; set; } 36 | 37 | public string? Memo { get; set; } 38 | } 39 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/V2rayMetricsVars.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | internal class V2rayMetricsVars 6 | { 7 | public V2rayMetricsVarsStats? stats { get; set; } 8 | } 9 | 10 | public class V2rayMetricsVarsStats 11 | { 12 | public Hashtable? outbound { get; set; } 13 | } 14 | 15 | public class V2rayMetricsVarsLink 16 | { 17 | public long downlink { get; set; } 18 | public long uplink { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/V2rayTcpRequest.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLib.Models; 2 | 3 | public class V2rayTcpRequest 4 | { 5 | /// 6 | /// 7 | /// 8 | public RequestHeaders headers { get; set; } 9 | } 10 | 11 | public class RequestHeaders 12 | { 13 | /// 14 | /// 15 | /// 16 | public List Host { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Models/VmessQRCode.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace ServiceLib.Models; 4 | 5 | /// 6 | /// https://github.com/2dust/v2rayN/wiki/ 7 | /// 8 | [Serializable] 9 | public class VmessQRCode 10 | { 11 | [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] 12 | public int v { get; set; } = 2; 13 | 14 | public string ps { get; set; } = string.Empty; 15 | 16 | public string add { get; set; } = string.Empty; 17 | 18 | [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] 19 | public int port { get; set; } = 0; 20 | 21 | public string id { get; set; } = string.Empty; 22 | 23 | [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] 24 | public int aid { get; set; } = 0; 25 | 26 | public string scy { get; set; } = string.Empty; 27 | 28 | public string net { get; set; } = string.Empty; 29 | 30 | public string type { get; set; } = string.Empty; 31 | 32 | public string host { get; set; } = string.Empty; 33 | 34 | public string path { get; set; } = string.Empty; 35 | 36 | public string tls { get; set; } = string.Empty; 37 | 38 | public string sni { get; set; } = string.Empty; 39 | 40 | public string alpn { get; set; } = string.Empty; 41 | 42 | public string fp { get; set; } = string.Empty; 43 | } 44 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/SampleClientConfig: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "access": "Vaccess.log", 4 | "error": "Verror.log", 5 | "loglevel": "warning" 6 | }, 7 | "inbounds": [], 8 | "outbounds": [ 9 | { 10 | "tag": "proxy", 11 | "protocol": "vmess", 12 | "settings": { 13 | "vnext": [{ 14 | "address": "", 15 | "port": 0, 16 | "users": [{ 17 | "id": "", 18 | "security": "auto" 19 | }] 20 | }], 21 | "servers": [{ 22 | "address": "", 23 | "method": "", 24 | "ota": false, 25 | "password": "", 26 | "port": 0, 27 | "level": 1 28 | }] 29 | }, 30 | "streamSettings": { 31 | "network": "tcp" 32 | }, 33 | "mux": { 34 | "enabled": false 35 | } 36 | }, 37 | { 38 | "protocol": "freedom", 39 | "tag": "direct" 40 | }, 41 | { 42 | "protocol": "blackhole", 43 | "tag": "block" 44 | } 45 | ], 46 | "routing": { 47 | "domainStrategy": "IPIfNonMatch", 48 | "rules": [ 49 | { 50 | "inboundTag": [ 51 | "api" 52 | ], 53 | "outboundTag": "api", 54 | "type": "field" 55 | } 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/SampleHttpRequest: -------------------------------------------------------------------------------- 1 | {"version":"1.1","method":"GET","path":[$requestPath$],"headers":{"Host":[$requestHost$],"User-Agent":[$requestUserAgent$],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}} -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/SampleHttpResponse: -------------------------------------------------------------------------------- 1 | {"version":"1.1","status":"200","reason":"OK","headers":{"Content-Type":["application/octet-stream","video/mpeg"],"Transfer-Encoding":["chunked"],"Connection":["keep-alive"],"Pragma":"no-cache"}} -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/SampleInbound: -------------------------------------------------------------------------------- 1 | { 2 | "tag": "tag1", 3 | "port": 10808, 4 | "protocol": "socks", 5 | "listen": "127.0.0.1", 6 | "settings": { 7 | "auth": "noauth", 8 | "udp": true, 9 | "allowTransparent": false 10 | }, 11 | "sniffing": { 12 | "enabled": true, 13 | "destOverride": [ 14 | "http", 15 | "tls" 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/SampleOutbound: -------------------------------------------------------------------------------- 1 | { 2 | "tag": "proxy", 3 | "protocol": "vmess", 4 | "settings": { 5 | "vnext": [ 6 | { 7 | "address": "v2ray.cool", 8 | "port": 10086, 9 | "users": [ 10 | { 11 | "id": "a3482e88-686a-4a58-8126-99c9df64b7bf", 12 | "security": "auto" 13 | } 14 | ] 15 | } 16 | ], 17 | "servers": [ 18 | { 19 | "address": "v2ray.cool", 20 | "method": "chacha20", 21 | "ota": false, 22 | "password": "123456", 23 | "port": 10086, 24 | "level": 1 25 | } 26 | ] 27 | }, 28 | "streamSettings": { 29 | "network": "tcp" 30 | }, 31 | "mux": { 32 | "enabled": false 33 | } 34 | } -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/SingboxSampleClientConfig: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "level": "debug", 4 | "timestamp": true 5 | }, 6 | "inbounds": [], 7 | "outbounds": [ 8 | { 9 | "type": "vless", 10 | "tag": "proxy", 11 | "server": "", 12 | "server_port": 443 13 | }, 14 | { 15 | "type": "direct", 16 | "tag": "direct" 17 | }, 18 | { 19 | "type": "block", 20 | "tag": "block" 21 | }, 22 | { 23 | "tag": "dns_out", 24 | "type": "dns" 25 | } 26 | ], 27 | "route": { 28 | "rules": [ 29 | { 30 | "protocol": [ "dns" ], 31 | "outbound": "dns_out" 32 | } 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/SingboxSampleOutbound: -------------------------------------------------------------------------------- 1 | { 2 | "type": "vless", 3 | "tag": "proxy", 4 | "server": "", 5 | "server_port": 443 6 | } -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/clash_mixin_yaml: -------------------------------------------------------------------------------- 1 | # 2 | # 配置文件内容不会被修改,混合行为只会发生在内存中 3 | # 4 | # 注意下面缩进,请用支持yaml显示的编辑器打开 5 | # 6 | # 使用clash配置文件关键字则覆盖原配置 7 | # 8 | # removed-rules 循环匹配rules数组每行,符合则移除当前行 (此规则请放最前面) 9 | # 10 | # append-rules 数组合并至原配置rules数组后 11 | # prepend-rules 数组合并至原配置rules数组前 12 | # append-proxies 数组合并至原配置proxies数组后 13 | # prepend-proxies 数组合并至原配置proxies数组前 14 | # append-proxy-groups 数组合并至原配置proxy-groups数组后 15 | # prepend-proxy-groups 数组合并至原配置proxy-groups数组前 16 | # append-rule-providers 数组合并至原配置rule-providers数组后 17 | # prepend-rule-providers 数组合并至原配置rule-providers数组前 18 | # 19 | 20 | dns: 21 | enable: true 22 | enhanced-mode: fake-ip 23 | nameserver: 24 | - 114.114.114.114 25 | - 223.5.5.5 26 | - 8.8.8.8 27 | fallback: [] 28 | fake-ip-filter: 29 | - +.stun.*.* 30 | - +.stun.*.*.* 31 | - +.stun.*.*.*.* 32 | - +.stun.*.*.*.*.* 33 | - "*.n.n.srv.nintendo.net" 34 | - +.stun.playstation.net 35 | - xbox.*.*.microsoft.com 36 | - "*.*.xboxlive.com" 37 | - "*.msftncsi.com" 38 | - "*.msftconnecttest.com" 39 | - WORKGROUP -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/clash_tun_yaml: -------------------------------------------------------------------------------- 1 | tun: 2 | enable: true 3 | stack: gvisor 4 | dns-hijack: 5 | - 0.0.0.0:53 6 | auto-route: true 7 | auto-detect-interface: true 8 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/custom_routing_global: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "remarks": "阻断udp443", 4 | "outboundTag": "block", 5 | "port": "443", 6 | "network": "udp" 7 | }, 8 | { 9 | "remarks": "绕过局域网IP", 10 | "outboundTag": "direct", 11 | "ip": [ 12 | "geoip:private" 13 | ] 14 | }, 15 | { 16 | "remarks": "绕过局域网域名", 17 | "outboundTag": "direct", 18 | "domain": [ 19 | "geosite:private" 20 | ] 21 | }, 22 | { 23 | "remarks": "最终代理", 24 | "port": "0-65535", 25 | "outboundTag": "proxy" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/custom_routing_white: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "remarks": "Google cn", 4 | "outboundTag": "proxy", 5 | "domain": [ 6 | "domain:googleapis.cn", 7 | "domain:gstatic.com" 8 | ] 9 | }, 10 | { 11 | "remarks": "阻断udp443", 12 | "outboundTag": "block", 13 | "port": "443", 14 | "network": "udp" 15 | }, 16 | { 17 | "remarks": "绕过局域网IP", 18 | "outboundTag": "direct", 19 | "ip": [ 20 | "geoip:private" 21 | ] 22 | }, 23 | { 24 | "remarks": "绕过局域网域名", 25 | "outboundTag": "direct", 26 | "domain": [ 27 | "geosite:private" 28 | ] 29 | }, 30 | { 31 | "remarks": "绕过中国公共DNSIP", 32 | "outboundTag": "direct", 33 | "ip": [ 34 | "223.5.5.5", 35 | "223.6.6.6", 36 | "2400:3200::1", 37 | "2400:3200:baba::1", 38 | "119.29.29.29", 39 | "1.12.12.12", 40 | "120.53.53.53", 41 | "2402:4e00::", 42 | "2402:4e00:1::", 43 | "180.76.76.76", 44 | "2400:da00::6666", 45 | "114.114.114.114", 46 | "114.114.115.115", 47 | "114.114.114.119", 48 | "114.114.115.119", 49 | "114.114.114.110", 50 | "114.114.115.110", 51 | "180.184.1.1", 52 | "180.184.2.2", 53 | "101.226.4.6", 54 | "218.30.118.6", 55 | "123.125.81.6", 56 | "140.207.198.6", 57 | "1.2.4.8", 58 | "210.2.4.8", 59 | "52.80.66.66", 60 | "117.50.22.22", 61 | "2400:7fc0:849e:200::4", 62 | "2404:c2c0:85d8:901::4", 63 | "117.50.10.10", 64 | "52.80.52.52", 65 | "2400:7fc0:849e:200::8", 66 | "2404:c2c0:85d8:901::8", 67 | "117.50.60.30", 68 | "52.80.60.30" 69 | ] 70 | }, 71 | { 72 | "remarks": "绕过中国公共DNS域名", 73 | "outboundTag": "direct", 74 | "domain": [ 75 | "domain:alidns.com", 76 | "domain:doh.pub", 77 | "domain:dot.pub", 78 | "domain:360.cn", 79 | "domain:onedns.net" 80 | ] 81 | }, 82 | { 83 | "remarks": "绕过中国IP", 84 | "outboundTag": "direct", 85 | "ip": [ 86 | "geoip:cn" 87 | ] 88 | }, 89 | { 90 | "remarks": "绕过中国域名", 91 | "outboundTag": "direct", 92 | "domain": [ 93 | "geosite:cn" 94 | ] 95 | } 96 | ] 97 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/dns_singbox_normal: -------------------------------------------------------------------------------- 1 | { 2 | "servers": [ 3 | { 4 | "tag": "remote", 5 | "address": "tcp://8.8.8.8", 6 | "strategy": "prefer_ipv4", 7 | "detour": "proxy" 8 | }, 9 | { 10 | "tag": "local", 11 | "address": "223.5.5.5", 12 | "strategy": "prefer_ipv4", 13 | "detour": "direct" 14 | }, 15 | { 16 | "tag": "block", 17 | "address": "rcode://success" 18 | } 19 | ], 20 | "rules": [ 21 | { 22 | "rule_set": [ 23 | "geosite-cn" 24 | ], 25 | "server": "local" 26 | } 27 | ], 28 | "final": "remote" 29 | } 30 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/dns_v2ray_normal: -------------------------------------------------------------------------------- 1 | { 2 | "hosts": { 3 | "dns.google": "8.8.8.8", 4 | "proxy.example.com": "127.0.0.1" 5 | }, 6 | "servers": [ 7 | { 8 | "address": "1.1.1.1", 9 | "skipFallback": true, 10 | "domains": [ 11 | "domain:googleapis.cn", 12 | "domain:gstatic.com" 13 | ] 14 | }, 15 | { 16 | "address": "223.5.5.5", 17 | "skipFallback": true, 18 | "domains": [ 19 | "geosite:cn" 20 | ], 21 | "expectIPs": [ 22 | "geoip:cn" 23 | ] 24 | }, 25 | "1.1.1.1", 26 | "8.8.8.8", 27 | "https://dns.google/dns-query" 28 | ] 29 | } -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/linux_autostart_config: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Exec=$ExecPath$ 4 | Hidden=false 5 | NoDisplay=false 6 | X-GNOME-Autostart-enabled=true 7 | Name[en_US]=v2rayN 8 | Name=v2rayN 9 | Comment[en_US]=v2rayN 10 | Comment=v2rayN -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/proxy_set_osx_sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to set proxy 4 | set_proxy() { 5 | PROXY_IP=$1 6 | PROXY_PORT=$2 7 | 8 | shift 2 9 | BYPASS_DOMAINS=("$@") 10 | # If no bypass domains are provided, set it to empty by default 11 | if [ ${#BYPASS_DOMAINS[@]} -eq 0 ]; then 12 | BYPASS_DOMAINS=("") 13 | fi 14 | 15 | # Get all network service names 16 | SERVICES=$(networksetup -listallnetworkservices | grep -v '*') 17 | 18 | # Loop through each network service 19 | echo "$SERVICES" | while read -r SERVICE; do 20 | echo "Setting proxy for network service '$SERVICE'..." 21 | # Set HTTP proxy 22 | networksetup -setwebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT" 23 | 24 | # Set HTTPS proxy 25 | networksetup -setsecurewebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT" 26 | 27 | # Set SOCKS proxy 28 | networksetup -setsocksfirewallproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT" 29 | 30 | # Set bypass domains 31 | networksetup -setproxybypassdomains "$SERVICE" "${BYPASS_DOMAINS[@]}" 32 | echo "Proxy for network service '$SERVICE' has been set to $PROXY_IP:$PROXY_PORT" 33 | done 34 | echo "Proxy settings for all network services are complete!" 35 | } 36 | 37 | # Function to disable proxy 38 | clear_proxy() { 39 | # Get all network service names 40 | SERVICES=$(networksetup -listallnetworkservices | grep -v '*') 41 | 42 | # Loop through each network service 43 | echo "$SERVICES" | while read -r SERVICE; do 44 | echo "Disabling proxy and clearing bypass domains for network service '$SERVICE'..." 45 | # Disable HTTP proxy 46 | networksetup -setwebproxystate "$SERVICE" off 47 | 48 | # Disable HTTPS proxy 49 | networksetup -setsecurewebproxystate "$SERVICE" off 50 | 51 | # Disable SOCKS proxy 52 | networksetup -setsocksfirewallproxystate "$SERVICE" off 53 | 54 | echo "Proxy for network service '$SERVICE' has been disabled" 55 | done 56 | echo "Proxy for all network services has been disabled!" 57 | } 58 | 59 | # Main script logic 60 | if [ "$1" == "set" ]; then 61 | # Check if enough parameters are passed for setting proxy 62 | if [ "$#" -lt 3 ]; then 63 | echo "Usage: $0 set [Bypass Domain 1 Bypass Domain 2 ...]" 64 | exit 1 65 | fi 66 | set_proxy "$2" "$3" "${@:4}" 67 | elif [ "$1" == "clear" ]; then 68 | clear_proxy 69 | else 70 | echo "Usage:" 71 | echo " To set proxy: $0 set [Bypass Domain 1 Bypass Domain 2 ...]" 72 | echo " To clear proxy: $0 clear" 73 | exit 1 74 | fi 75 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/tun_singbox_dns: -------------------------------------------------------------------------------- 1 | { 2 | "servers": [ 3 | { 4 | "tag": "remote", 5 | "address": "tcp://8.8.8.8", 6 | "strategy": "prefer_ipv4", 7 | "detour": "proxy" 8 | }, 9 | { 10 | "tag": "local", 11 | "address": "223.5.5.5", 12 | "strategy": "prefer_ipv4", 13 | "detour": "direct" 14 | }, 15 | { 16 | "tag": "block", 17 | "address": "rcode://success" 18 | } 19 | ], 20 | "rules": [ 21 | { 22 | "rule_set": [ 23 | "geosite-cn", 24 | "geosite-geolocation-cn" 25 | ], 26 | "server": "local" 27 | } 28 | ], 29 | "final": "remote" 30 | } 31 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/tun_singbox_inbound: -------------------------------------------------------------------------------- 1 | { 2 | "type": "tun", 3 | "tag": "tun-in", 4 | "interface_name": "singbox_tun", 5 | "address": [ 6 | "172.18.0.1/30", 7 | "fdfe:dcba:9876::1/126" 8 | ], 9 | "mtu": 9000, 10 | "auto_route": true, 11 | "strict_route": false, 12 | "stack": "system", 13 | "sniff": true 14 | } -------------------------------------------------------------------------------- /v2rayN/ServiceLib/Sample/tun_singbox_rules: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "network": "udp", 4 | "port": [ 5 | 135, 6 | 137, 7 | 138, 8 | 139, 9 | 5353 10 | ], 11 | "outbound": "block" 12 | }, 13 | { 14 | "ip_cidr": [ 15 | "224.0.0.0/3", 16 | "ff00::/8" 17 | ], 18 | "outbound": "block" 19 | } 20 | ] -------------------------------------------------------------------------------- /v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive; 2 | using ReactiveUI; 3 | 4 | namespace ServiceLib.ViewModels; 5 | 6 | public class GlobalHotkeySettingViewModel : MyReactiveObject 7 | { 8 | private readonly List _globalHotkeys; 9 | 10 | public ReactiveCommand SaveCmd { get; } 11 | 12 | public GlobalHotkeySettingViewModel(Func>? updateView) 13 | { 14 | _config = AppHandler.Instance.Config; 15 | _updateView = updateView; 16 | 17 | _globalHotkeys = JsonUtils.DeepCopy(_config.GlobalHotkeys); 18 | 19 | SaveCmd = ReactiveCommand.CreateFromTask(async () => 20 | { 21 | await SaveSettingAsync(); 22 | }); 23 | } 24 | 25 | public KeyEventItem GetKeyEventItem(EGlobalHotkey eg) 26 | { 27 | var item = _globalHotkeys.FirstOrDefault((it) => it.EGlobalHotkey == eg); 28 | if (item != null) 29 | { 30 | return item; 31 | } 32 | 33 | item = new() 34 | { 35 | EGlobalHotkey = eg, 36 | Control = false, 37 | Alt = false, 38 | Shift = false, 39 | KeyCode = null 40 | }; 41 | _globalHotkeys.Add(item); 42 | 43 | return item; 44 | } 45 | 46 | public void ResetKeyEventItem() 47 | { 48 | _globalHotkeys.Clear(); 49 | } 50 | 51 | private async Task SaveSettingAsync() 52 | { 53 | _config.GlobalHotkeys = _globalHotkeys; 54 | 55 | if (await ConfigHandler.SaveConfig(_config) == 0) 56 | { 57 | _updateView?.Invoke(EViewAction.CloseWindow, null); 58 | } 59 | else 60 | { 61 | NoticeHandler.Instance.Enqueue(ResUI.OperationFailed); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/ViewModels/RoutingRuleDetailsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive; 2 | using ReactiveUI; 3 | using ReactiveUI.Fody.Helpers; 4 | 5 | namespace ServiceLib.ViewModels; 6 | 7 | public class RoutingRuleDetailsViewModel : MyReactiveObject 8 | { 9 | public IList ProtocolItems { get; set; } 10 | public IList InboundTagItems { get; set; } 11 | 12 | [Reactive] 13 | public RulesItem SelectedSource { get; set; } 14 | 15 | [Reactive] 16 | public string Domain { get; set; } 17 | 18 | [Reactive] 19 | public string IP { get; set; } 20 | 21 | [Reactive] 22 | public string Process { get; set; } 23 | 24 | [Reactive] 25 | public bool AutoSort { get; set; } 26 | 27 | public ReactiveCommand SaveCmd { get; } 28 | 29 | public RoutingRuleDetailsViewModel(RulesItem rulesItem, Func>? updateView) 30 | { 31 | _config = AppHandler.Instance.Config; 32 | _updateView = updateView; 33 | 34 | SaveCmd = ReactiveCommand.CreateFromTask(async () => 35 | { 36 | await SaveRulesAsync(); 37 | }); 38 | 39 | if (rulesItem.Id.IsNullOrEmpty()) 40 | { 41 | rulesItem.Id = Utils.GetGuid(false); 42 | rulesItem.OutboundTag = Global.ProxyTag; 43 | rulesItem.Enabled = true; 44 | SelectedSource = rulesItem; 45 | } 46 | else 47 | { 48 | SelectedSource = rulesItem; 49 | } 50 | 51 | Domain = Utils.List2String(SelectedSource.Domain, true); 52 | IP = Utils.List2String(SelectedSource.Ip, true); 53 | Process = Utils.List2String(SelectedSource.Process, true); 54 | } 55 | 56 | private async Task SaveRulesAsync() 57 | { 58 | Domain = Utils.Convert2Comma(Domain); 59 | IP = Utils.Convert2Comma(IP); 60 | Process = Utils.Convert2Comma(Process); 61 | 62 | if (AutoSort) 63 | { 64 | SelectedSource.Domain = Utils.String2ListSorted(Domain); 65 | SelectedSource.Ip = Utils.String2ListSorted(IP); 66 | SelectedSource.Process = Utils.String2ListSorted(Process); 67 | } 68 | else 69 | { 70 | SelectedSource.Domain = Utils.String2List(Domain); 71 | SelectedSource.Ip = Utils.String2List(IP); 72 | SelectedSource.Process = Utils.String2List(Process); 73 | } 74 | SelectedSource.Protocol = ProtocolItems?.ToList(); 75 | SelectedSource.InboundTag = InboundTagItems?.ToList(); 76 | 77 | var hasRule = SelectedSource.Domain?.Count > 0 78 | || SelectedSource.Ip?.Count > 0 79 | || SelectedSource.Protocol?.Count > 0 80 | || SelectedSource.Process?.Count > 0 81 | || SelectedSource.Port.IsNotEmpty() 82 | || SelectedSource.Network.IsNotEmpty(); 83 | 84 | if (!hasRule) 85 | { 86 | NoticeHandler.Instance.Enqueue(string.Format(ResUI.RoutingRuleDetailRequiredTips, "Network/Port/Protocol/Domain/IP/Process")); 87 | return; 88 | } 89 | //NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); 90 | await _updateView?.Invoke(EViewAction.CloseWindow, null); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /v2rayN/ServiceLib/ViewModels/SubEditViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive; 2 | using ReactiveUI; 3 | using ReactiveUI.Fody.Helpers; 4 | 5 | namespace ServiceLib.ViewModels; 6 | 7 | public class SubEditViewModel : MyReactiveObject 8 | { 9 | [Reactive] 10 | public SubItem SelectedSource { get; set; } 11 | 12 | public ReactiveCommand SaveCmd { get; } 13 | 14 | public SubEditViewModel(SubItem subItem, Func>? updateView) 15 | { 16 | _config = AppHandler.Instance.Config; 17 | _updateView = updateView; 18 | 19 | SaveCmd = ReactiveCommand.CreateFromTask(async () => 20 | { 21 | await SaveSubAsync(); 22 | }); 23 | 24 | SelectedSource = subItem.Id.IsNullOrEmpty() ? subItem : JsonUtils.DeepCopy(subItem); 25 | } 26 | 27 | private async Task SaveSubAsync() 28 | { 29 | var remarks = SelectedSource.Remarks; 30 | if (remarks.IsNullOrEmpty()) 31 | { 32 | NoticeHandler.Instance.Enqueue(ResUI.PleaseFillRemarks); 33 | return; 34 | } 35 | 36 | var url = SelectedSource.Url; 37 | if (url.IsNotEmpty()) 38 | { 39 | var uri = Utils.TryUri(url); 40 | if (uri == null) 41 | { 42 | NoticeHandler.Instance.Enqueue(ResUI.InvalidUrlTip); 43 | return; 44 | } 45 | //Do not allow http protocol 46 | if (url.StartsWith(Global.HttpProtocol) && !Utils.IsPrivateNetwork(uri.IdnHost)) 47 | { 48 | NoticeHandler.Instance.Enqueue(ResUI.InsecureUrlProtocol); 49 | //return; 50 | } 51 | } 52 | 53 | if (await ConfigHandler.AddSubItem(_config, SelectedSource) == 0) 54 | { 55 | NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); 56 | _updateView?.Invoke(EViewAction.CloseWindow, null); 57 | } 58 | else 59 | { 60 | NoticeHandler.Instance.Enqueue(ResUI.OperationFailed); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.Markup.Xaml; 4 | using Splat; 5 | using v2rayN.Desktop.Common; 6 | using v2rayN.Desktop.Views; 7 | 8 | namespace v2rayN.Desktop; 9 | 10 | public partial class App : Application 11 | { 12 | public override void Initialize() 13 | { 14 | if (!AppHandler.Instance.InitApp()) 15 | { 16 | Environment.Exit(0); 17 | return; 18 | } 19 | AvaloniaXamlLoader.Load(this); 20 | 21 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 22 | TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 23 | 24 | var ViewModel = new StatusBarViewModel(null); 25 | Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(StatusBarViewModel)); 26 | DataContext = ViewModel; 27 | } 28 | 29 | public override void OnFrameworkInitializationCompleted() 30 | { 31 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 32 | { 33 | AppHandler.Instance.InitComponents(); 34 | 35 | desktop.Exit += OnExit; 36 | desktop.MainWindow = new MainWindow(); 37 | } 38 | 39 | base.OnFrameworkInitializationCompleted(); 40 | } 41 | 42 | private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 43 | { 44 | if (e.ExceptionObject != null) 45 | { 46 | Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject); 47 | } 48 | } 49 | 50 | private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) 51 | { 52 | Logging.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception); 53 | } 54 | 55 | private void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs e) 56 | { 57 | } 58 | 59 | private async void MenuAddServerViaClipboardClick(object? sender, EventArgs e) 60 | { 61 | if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 62 | { 63 | if (desktop.MainWindow != null) 64 | { 65 | var clipboardData = await AvaUtils.GetClipboardData(desktop.MainWindow); 66 | if (clipboardData.IsNullOrEmpty()) 67 | { 68 | return; 69 | } 70 | var service = Locator.Current.GetService(); 71 | if (service != null) 72 | { 73 | _ = service.AddServerViaClipboardAsync(clipboardData); 74 | } 75 | } 76 | } 77 | } 78 | 79 | private async void MenuExit_Click(object? sender, EventArgs e) 80 | { 81 | var service = Locator.Current.GetService(); 82 | if (service != null) 83 | { 84 | await service.MyAppExitAsync(true); 85 | } 86 | service?.Shutdown(true); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Assets/Fonts/NotoSansSC-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/Assets/Fonts/NotoSansSC-Regular.ttf -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Assets/GlobalStyles.axaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 21 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Assets/NotifyIcon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/Assets/NotifyIcon1.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Assets/NotifyIcon2.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/Assets/NotifyIcon2.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Assets/NotifyIcon3.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/Assets/NotifyIcon3.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Assets/NotifyIcon4.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/Assets/NotifyIcon4.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Assets/v2rayN.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/Assets/v2rayN.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Common/AppBuilderExtension.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Media; 3 | 4 | namespace v2rayN.Desktop.Common; 5 | 6 | public static class AppBuilderExtension 7 | { 8 | public static AppBuilder WithFontByDefault(this AppBuilder appBuilder) 9 | { 10 | var uri = Path.Combine(Global.AvaAssets, "Fonts#Noto Sans SC"); 11 | return appBuilder.With(new FontManagerOptions() 12 | { 13 | //DefaultFamilyName = uri, 14 | FontFallbacks = new[] { new FontFallback { FontFamily = new FontFamily(uri) } } 15 | }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Common/AvaUtils.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Input; 4 | using Avalonia.Media.Imaging; 5 | using Avalonia.Platform; 6 | 7 | namespace v2rayN.Desktop.Common; 8 | 9 | internal class AvaUtils 10 | { 11 | public static async Task GetClipboardData(Window owner) 12 | { 13 | try 14 | { 15 | var clipboard = TopLevel.GetTopLevel(owner)?.Clipboard; 16 | if (clipboard == null) 17 | { 18 | return null; 19 | } 20 | 21 | return await clipboard.GetTextAsync(); 22 | } 23 | catch 24 | { 25 | return null; 26 | } 27 | } 28 | 29 | public static async Task SetClipboardData(Visual? visual, string strData) 30 | { 31 | try 32 | { 33 | var clipboard = TopLevel.GetTopLevel(visual)?.Clipboard; 34 | if (clipboard == null) 35 | return; 36 | var dataObject = new DataObject(); 37 | dataObject.Set(DataFormats.Text, strData); 38 | await clipboard.SetDataObjectAsync(dataObject); 39 | } 40 | catch 41 | { 42 | } 43 | } 44 | 45 | public static WindowIcon GetAppIcon(ESysProxyType sysProxyType) 46 | { 47 | var index = (int)sysProxyType + 1; 48 | var fileName = Utils.GetPath($"NotifyIcon{index}.ico"); 49 | if (File.Exists(fileName)) 50 | { 51 | return new(fileName); 52 | } 53 | 54 | var uri = new Uri(Path.Combine(Global.AvaAssets, $"NotifyIcon{index}.ico")); 55 | using var bitmap = new Bitmap(AssetLoader.Open(uri)); 56 | return new(bitmap); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Common/UI.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Platform.Storage; 3 | using MsBox.Avalonia; 4 | using MsBox.Avalonia.Enums; 5 | 6 | namespace v2rayN.Desktop.Common; 7 | 8 | internal class UI 9 | { 10 | private static readonly string caption = Global.AppName; 11 | 12 | public static async Task ShowYesNo(Window owner, string msg) 13 | { 14 | var box = MessageBoxManager.GetMessageBoxStandard(caption, msg, ButtonEnum.YesNo); 15 | return await box.ShowWindowDialogAsync(owner); 16 | } 17 | 18 | public static async Task OpenFileDialog(Window owner, FilePickerFileType? filter) 19 | { 20 | var sp = GetStorageProvider(owner); 21 | if (sp is null) 22 | { 23 | return null; 24 | } 25 | 26 | // Start async operation to open the dialog. 27 | var files = await sp.OpenFilePickerAsync(new FilePickerOpenOptions 28 | { 29 | AllowMultiple = false, 30 | FileTypeFilter = filter is null ? [FilePickerFileTypes.All, FilePickerFileTypes.ImagePng] : [filter] 31 | }); 32 | 33 | return files.FirstOrDefault()?.TryGetLocalPath(); 34 | } 35 | 36 | public static async Task SaveFileDialog(Window owner, string filter) 37 | { 38 | var sp = GetStorageProvider(owner); 39 | if (sp is null) 40 | { 41 | return null; 42 | } 43 | 44 | // Start async operation to open the dialog. 45 | var files = await sp.SaveFilePickerAsync(new FilePickerSaveOptions 46 | { 47 | }); 48 | 49 | return files?.TryGetLocalPath(); 50 | } 51 | 52 | private static IStorageProvider? GetStorageProvider(Window owner) 53 | { 54 | var topLevel = TopLevel.GetTopLevel(owner); 55 | return topLevel?.StorageProvider; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 21 | 26 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Input; 2 | using Avalonia.Interactivity; 3 | 4 | namespace v2rayN.Desktop.Controls; 5 | 6 | public class AutoCompleteBox : Avalonia.Controls.AutoCompleteBox 7 | { 8 | static AutoCompleteBox() 9 | { 10 | MinimumPrefixLengthProperty.OverrideDefaultValue(0); 11 | } 12 | 13 | public AutoCompleteBox() 14 | { 15 | AddHandler(PointerPressedEvent, OnBoxPointerPressed, RoutingStrategies.Tunnel); 16 | } 17 | 18 | private void OnBoxPointerPressed(object? sender, PointerPressedEventArgs e) 19 | { 20 | if (Equals(sender, this) && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) 21 | { 22 | SetCurrentValue(IsDropDownOpenProperty, true); 23 | } 24 | } 25 | 26 | protected override void OnGotFocus(GotFocusEventArgs e) 27 | { 28 | base.OnGotFocus(e); 29 | if (IsDropDownOpen) 30 | { 31 | return; 32 | } 33 | SetCurrentValue(IsDropDownOpenProperty, true); 34 | } 35 | 36 | public void Clear() 37 | { 38 | SetCurrentValue(SelectedItemProperty, null); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Converters/DelayColorConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using Avalonia.Data.Converters; 3 | using Avalonia.Media; 4 | 5 | namespace v2rayN.Desktop.Converters; 6 | 7 | public class DelayColorConverter : IValueConverter 8 | { 9 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 10 | { 11 | _ = int.TryParse(value?.ToString(), out var delay); 12 | 13 | return delay switch 14 | { 15 | <= 0 => new SolidColorBrush(Colors.Red), 16 | <= 500 => new SolidColorBrush(Colors.Green), 17 | _ => new SolidColorBrush(Colors.IndianRed) 18 | }; 19 | } 20 | 21 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) 22 | { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using ServiceLib; 2 | global using ServiceLib.Base; 3 | global using ServiceLib.Common; 4 | global using ServiceLib.Enums; 5 | global using ServiceLib.Handler; 6 | global using ServiceLib.Models; 7 | global using ServiceLib.Resx; 8 | global using ServiceLib.ViewModels; -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Handler/HotkeyHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Linq; 2 | using Avalonia.Input; 3 | using Avalonia.ReactiveUI; 4 | using Avalonia.Win32.Input; 5 | using GlobalHotKeys; 6 | 7 | namespace v2rayN.Desktop.Handler; 8 | 9 | public sealed class HotkeyHandler 10 | { 11 | private static readonly Lazy _instance = new(() => new()); 12 | public static HotkeyHandler Instance = _instance.Value; 13 | private readonly Dictionary _hotkeyTriggerDic = new(); 14 | private HotKeyManager? _hotKeyManager; 15 | 16 | private Config? _config; 17 | 18 | private event Action? _updateFunc; 19 | 20 | public bool IsPause { get; set; } = false; 21 | 22 | public void Init(Config config, Action updateFunc) 23 | { 24 | _config = config; 25 | _updateFunc = updateFunc; 26 | 27 | Register(); 28 | } 29 | 30 | public void Dispose() 31 | { 32 | _hotKeyManager?.Dispose(); 33 | } 34 | 35 | private void Register() 36 | { 37 | if (_config.GlobalHotkeys.Any(t => t.KeyCode > 0) == false) 38 | { 39 | return; 40 | } 41 | _hotKeyManager ??= new GlobalHotKeys.HotKeyManager(); 42 | _hotkeyTriggerDic.Clear(); 43 | 44 | foreach (var item in _config.GlobalHotkeys) 45 | { 46 | if (item.KeyCode is null or 0) 47 | { 48 | continue; 49 | } 50 | 51 | var vKey = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode); 52 | var modifiers = Modifiers.None; 53 | if (item.Control) 54 | { 55 | modifiers |= Modifiers.Control; 56 | } 57 | if (item.Shift) 58 | { 59 | modifiers |= Modifiers.Shift; 60 | } 61 | if (item.Alt) 62 | { 63 | modifiers |= Modifiers.Alt; 64 | } 65 | 66 | var result = _hotKeyManager?.Register((VirtualKeyCode)vKey, modifiers); 67 | if (result?.IsSuccessful == true) 68 | { 69 | _hotkeyTriggerDic.Add(result.Id, item.EGlobalHotkey); 70 | } 71 | } 72 | 73 | _hotKeyManager?.HotKeyPressed 74 | .ObserveOn(AvaloniaScheduler.Instance) 75 | .Subscribe(OnNext); 76 | } 77 | 78 | private void OnNext(HotKey key) 79 | { 80 | if (_updateFunc == null || IsPause) 81 | { 82 | return; 83 | } 84 | 85 | if (_hotkeyTriggerDic.TryGetValue(key.Id, out var value)) 86 | { 87 | _updateFunc?.Invoke(value); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Program.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.ReactiveUI; 3 | using v2rayN.Desktop.Common; 4 | 5 | namespace v2rayN.Desktop; 6 | 7 | internal class Program 8 | { 9 | public static EventWaitHandle ProgramStarted; 10 | 11 | // Initialization code. Don't use any Avalonia, third-party APIs or any 12 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 13 | // yet and stuff might break. 14 | [STAThread] 15 | public static void Main(string[] args) 16 | { 17 | OnStartup(args); 18 | 19 | BuildAvaloniaApp() 20 | .StartWithClassicDesktopLifetime(args); 21 | } 22 | 23 | private static void OnStartup(string[]? Args) 24 | { 25 | if (Utils.IsWindows()) 26 | { 27 | var exePathKey = Utils.GetMd5(Utils.GetExePath()); 28 | var rebootas = (Args ?? []).Any(t => t == Global.RebootAs); 29 | ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out var bCreatedNew); 30 | if (!rebootas && !bCreatedNew) 31 | { 32 | ProgramStarted.Set(); 33 | Environment.Exit(0); 34 | return; 35 | } 36 | } 37 | else 38 | { 39 | _ = new Mutex(true, "v2rayN", out var bOnlyOneInstance); 40 | if (!bOnlyOneInstance) 41 | { 42 | Environment.Exit(0); 43 | return; 44 | } 45 | } 46 | } 47 | 48 | // Avalonia configuration, don't remove; also used by visual designer. 49 | public static AppBuilder BuildAvaloniaApp() 50 | => AppBuilder.Configure() 51 | .UsePlatformDetect() 52 | //.WithInterFont() 53 | .WithFontByDefault() 54 | .LogToTrace() 55 | .UseReactiveUI() 56 | .With(new MacOSPlatformOptions { ShowInDock = false }); 57 | } 58 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/AddServer2Window.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia.Interactivity; 3 | using Avalonia.ReactiveUI; 4 | using ReactiveUI; 5 | using v2rayN.Desktop.Common; 6 | 7 | namespace v2rayN.Desktop.Views; 8 | 9 | public partial class AddServer2Window : ReactiveWindow 10 | { 11 | public AddServer2Window() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | public AddServer2Window(ProfileItem profileItem) 17 | { 18 | InitializeComponent(); 19 | 20 | this.Loaded += Window_Loaded; 21 | btnCancel.Click += (s, e) => this.Close(); 22 | ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler); 23 | 24 | foreach (ECoreType it in Enum.GetValues(typeof(ECoreType))) 25 | { 26 | if (it == ECoreType.v2rayN) 27 | continue; 28 | cmbCoreType.Items.Add(it.ToString()); 29 | } 30 | cmbCoreType.Items.Add(string.Empty); 31 | 32 | this.WhenActivated(disposables => 33 | { 34 | this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables); 35 | this.Bind(ViewModel, vm => vm.SelectedSource.Address, v => v.txtAddress.Text).DisposeWith(disposables); 36 | this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables); 37 | this.Bind(ViewModel, vm => vm.SelectedSource.DisplayLog, v => v.togDisplayLog.IsChecked).DisposeWith(disposables); 38 | this.Bind(ViewModel, vm => vm.SelectedSource.PreSocksPort, v => v.txtPreSocksPort.Text).DisposeWith(disposables); 39 | 40 | this.BindCommand(ViewModel, vm => vm.BrowseServerCmd, v => v.btnBrowse).DisposeWith(disposables); 41 | this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables); 42 | this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables); 43 | }); 44 | } 45 | 46 | private async Task UpdateViewHandler(EViewAction action, object? obj) 47 | { 48 | switch (action) 49 | { 50 | case EViewAction.CloseWindow: 51 | this.Close(true); 52 | break; 53 | 54 | case EViewAction.BrowseServer: 55 | var fileName = await UI.OpenFileDialog(this, null); 56 | if (fileName.IsNullOrEmpty()) 57 | { 58 | return false; 59 | } 60 | ViewModel?.BrowseServer(fileName); 61 | break; 62 | } 63 | 64 | return await Task.FromResult(true); 65 | } 66 | 67 | private void Window_Loaded(object? sender, RoutedEventArgs e) 68 | { 69 | txtRemarks.Focus(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/BackupAndRestoreView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia.Controls; 3 | using Avalonia.Interactivity; 4 | using Avalonia.ReactiveUI; 5 | using ReactiveUI; 6 | using v2rayN.Desktop.Common; 7 | 8 | namespace v2rayN.Desktop.Views; 9 | 10 | public partial class BackupAndRestoreView : ReactiveUserControl 11 | { 12 | private Window? _window; 13 | 14 | public BackupAndRestoreView() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | public BackupAndRestoreView(Window window) 20 | { 21 | _window = window; 22 | 23 | InitializeComponent(); 24 | menuLocalBackup.Click += MenuLocalBackup_Click; 25 | menuLocalRestore.Click += MenuLocalRestore_Click; 26 | 27 | ViewModel = new BackupAndRestoreViewModel(UpdateViewHandler); 28 | 29 | this.WhenActivated(disposables => 30 | { 31 | this.Bind(ViewModel, vm => vm.OperationMsg, v => v.txtMsg.Text).DisposeWith(disposables); 32 | 33 | this.Bind(ViewModel, vm => vm.SelectedSource.Url, v => v.txtWebDavUrl.Text).DisposeWith(disposables); 34 | this.Bind(ViewModel, vm => vm.SelectedSource.UserName, v => v.txtWebDavUserName.Text).DisposeWith(disposables); 35 | this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtWebDavPassword.Text).DisposeWith(disposables); 36 | this.Bind(ViewModel, vm => vm.SelectedSource.DirName, v => v.txtWebDavDirName.Text).DisposeWith(disposables); 37 | 38 | this.BindCommand(ViewModel, vm => vm.WebDavCheckCmd, v => v.menuWebDavCheck).DisposeWith(disposables); 39 | 40 | this.BindCommand(ViewModel, vm => vm.RemoteBackupCmd, v => v.menuRemoteBackup).DisposeWith(disposables); 41 | this.BindCommand(ViewModel, vm => vm.RemoteRestoreCmd, v => v.menuRemoteRestore).DisposeWith(disposables); 42 | }); 43 | } 44 | 45 | private async void MenuLocalBackup_Click(object? sender, RoutedEventArgs e) 46 | { 47 | var fileName = await UI.SaveFileDialog(_window, "Zip|*.zip"); 48 | if (fileName.IsNullOrEmpty()) 49 | { 50 | return; 51 | } 52 | 53 | ViewModel?.LocalBackup(fileName); 54 | } 55 | 56 | private async void MenuLocalRestore_Click(object? sender, RoutedEventArgs e) 57 | { 58 | var fileName = await UI.OpenFileDialog(_window, null); 59 | if (fileName.IsNullOrEmpty()) 60 | { 61 | return; 62 | } 63 | 64 | ViewModel?.LocalRestore(fileName); 65 | } 66 | 67 | private async Task UpdateViewHandler(EViewAction action, object? obj) 68 | { 69 | return await Task.FromResult(true); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/CheckUpdateView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia.ReactiveUI; 3 | using Avalonia.Threading; 4 | using ReactiveUI; 5 | 6 | namespace v2rayN.Desktop.Views; 7 | 8 | public partial class CheckUpdateView : ReactiveUserControl 9 | { 10 | public CheckUpdateView() 11 | { 12 | InitializeComponent(); 13 | 14 | ViewModel = new CheckUpdateViewModel(UpdateViewHandler); 15 | 16 | this.WhenActivated(disposables => 17 | { 18 | this.OneWayBind(ViewModel, vm => vm.CheckUpdateModels, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables); 19 | 20 | this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables); 21 | this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdate).DisposeWith(disposables); 22 | }); 23 | } 24 | 25 | private async Task UpdateViewHandler(EViewAction action, object? obj) 26 | { 27 | switch (action) 28 | { 29 | case EViewAction.DispatcherCheckUpdate: 30 | if (obj is null) 31 | return false; 32 | Dispatcher.UIThread.Post(() => 33 | ViewModel?.UpdateViewResult((CheckUpdateModel)obj), 34 | DispatcherPriority.Default); 35 | break; 36 | 37 | case EViewAction.DispatcherCheckUpdateFinished: 38 | if (obj is null) 39 | return false; 40 | Dispatcher.UIThread.Post(() => 41 | ViewModel?.UpdateFinishedResult((bool)obj), 42 | DispatcherPriority.Default); 43 | break; 44 | } 45 | 46 | return await Task.FromResult(true); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/ClashConnectionsView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia.Controls; 3 | using Avalonia.Interactivity; 4 | using Avalonia.ReactiveUI; 5 | using Avalonia.Threading; 6 | using ReactiveUI; 7 | 8 | namespace v2rayN.Desktop.Views; 9 | 10 | public partial class ClashConnectionsView : ReactiveUserControl 11 | { 12 | public ClashConnectionsView() 13 | { 14 | InitializeComponent(); 15 | ViewModel = new ClashConnectionsViewModel(UpdateViewHandler); 16 | btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click; 17 | 18 | this.WhenActivated(disposables => 19 | { 20 | this.OneWayBind(ViewModel, vm => vm.ConnectionItems, v => v.lstConnections.ItemsSource).DisposeWith(disposables); 21 | this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstConnections.SelectedItem).DisposeWith(disposables); 22 | 23 | this.BindCommand(ViewModel, vm => vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables); 24 | this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables); 25 | 26 | this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables); 27 | this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables); 28 | this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables); 29 | }); 30 | } 31 | 32 | private async Task UpdateViewHandler(EViewAction action, object? obj) 33 | { 34 | switch (action) 35 | { 36 | case EViewAction.DispatcherRefreshConnections: 37 | if (obj is null) 38 | return false; 39 | Dispatcher.UIThread.Post(() => 40 | ViewModel?.RefreshConnections((List?)obj), 41 | DispatcherPriority.Default); 42 | break; 43 | } 44 | 45 | return await Task.FromResult(true); 46 | } 47 | 48 | private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e) 49 | { 50 | AutofitColumnWidth(); 51 | } 52 | 53 | private void AutofitColumnWidth() 54 | { 55 | try 56 | { 57 | foreach (var it in lstConnections.Columns) 58 | { 59 | it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); 60 | } 61 | } 62 | catch (Exception ex) 63 | { 64 | Logging.SaveLog("ClashConnectionsView", ex); 65 | } 66 | } 67 | 68 | private void btnClose_Click(object? sender, RoutedEventArgs e) 69 | { 70 | ViewModel?.ClashConnectionClose(false); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia.Interactivity; 3 | using Avalonia.ReactiveUI; 4 | using ReactiveUI; 5 | 6 | namespace v2rayN.Desktop.Views; 7 | 8 | public partial class DNSSettingWindow : ReactiveWindow 9 | { 10 | private static Config _config; 11 | 12 | public DNSSettingWindow() 13 | { 14 | InitializeComponent(); 15 | 16 | _config = AppHandler.Instance.Config; 17 | btnCancel.Click += (s, e) => this.Close(); 18 | ViewModel = new DNSSettingViewModel(UpdateViewHandler); 19 | 20 | Global.DomainStrategy4Freedoms.ForEach(it => 21 | { 22 | cmbdomainStrategy4Freedom.Items.Add(it); 23 | }); 24 | Global.SingboxDomainStrategy4Out.ForEach(it => 25 | { 26 | cmbdomainStrategy4Out.Items.Add(it); 27 | }); 28 | Global.DomainDNSAddress.ForEach(it => 29 | { 30 | cmbdomainDNSAddress.Items.Add(it); 31 | }); 32 | Global.SingboxDomainDNSAddress.ForEach(it => 33 | { 34 | cmbdomainDNSAddress2.Items.Add(it); 35 | }); 36 | 37 | this.WhenActivated(disposables => 38 | { 39 | this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables); 40 | this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.SelectedValue).DisposeWith(disposables); 41 | this.Bind(ViewModel, vm => vm.DomainDNSAddress, v => v.cmbdomainDNSAddress.SelectedValue).DisposeWith(disposables); 42 | this.Bind(ViewModel, vm => vm.NormalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables); 43 | 44 | this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.SelectedValue).DisposeWith(disposables); 45 | this.Bind(ViewModel, vm => vm.DomainDNSAddress2, v => v.cmbdomainDNSAddress2.SelectedValue).DisposeWith(disposables); 46 | this.Bind(ViewModel, vm => vm.NormalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables); 47 | this.Bind(ViewModel, vm => vm.TunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables); 48 | 49 | this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 50 | this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables); 51 | this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables); 52 | }); 53 | } 54 | 55 | private async Task UpdateViewHandler(EViewAction action, object? obj) 56 | { 57 | switch (action) 58 | { 59 | case EViewAction.CloseWindow: 60 | this.Close(true); 61 | break; 62 | } 63 | return await Task.FromResult(true); 64 | } 65 | 66 | private void linkDnsObjectDoc_Click(object? sender, RoutedEventArgs e) 67 | { 68 | ProcUtils.ProcessStart("https://xtls.github.io/config/dns.html#dnsobject"); 69 | } 70 | 71 | private void linkDnsSingboxObjectDoc_Click(object? sender, RoutedEventArgs e) 72 | { 73 | ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/"); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/MsgView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia.Interactivity; 3 | using Avalonia.ReactiveUI; 4 | using Avalonia.Threading; 5 | using ReactiveUI; 6 | using v2rayN.Desktop.Common; 7 | 8 | namespace v2rayN.Desktop.Views; 9 | 10 | public partial class MsgView : ReactiveUserControl 11 | { 12 | public MsgView() 13 | { 14 | InitializeComponent(); 15 | 16 | ViewModel = new MsgViewModel(UpdateViewHandler); 17 | 18 | this.WhenActivated(disposables => 19 | { 20 | this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables); 21 | this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables); 22 | }); 23 | } 24 | 25 | private async Task UpdateViewHandler(EViewAction action, object? obj) 26 | { 27 | switch (action) 28 | { 29 | case EViewAction.DispatcherShowMsg: 30 | if (obj is null) 31 | return false; 32 | 33 | Dispatcher.UIThread.Post(() => 34 | ShowMsg(obj), 35 | DispatcherPriority.ApplicationIdle); 36 | break; 37 | } 38 | return await Task.FromResult(true); 39 | } 40 | 41 | private void ShowMsg(object msg) 42 | { 43 | txtMsg.Text = msg.ToString(); 44 | if (togScrollToEnd.IsChecked ?? true) 45 | { 46 | txtMsg.CaretIndex = int.MaxValue; 47 | } 48 | } 49 | 50 | public void ClearMsg() 51 | { 52 | ViewModel?.ClearMsg(); 53 | txtMsg.Clear(); 54 | } 55 | 56 | private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e) 57 | { 58 | txtMsg.Focus(); 59 | txtMsg.SelectAll(); 60 | } 61 | 62 | private async void menuMsgViewCopy_Click(object? sender, RoutedEventArgs e) 63 | { 64 | var data = txtMsg.SelectedText.TrimEx(); 65 | await AvaUtils.SetClipboardData(this, data); 66 | } 67 | 68 | private async void menuMsgViewCopyAll_Click(object? sender, RoutedEventArgs e) 69 | { 70 | var data = txtMsg.Text.TrimEx(); 71 | await AvaUtils.SetClipboardData(this, data); 72 | } 73 | 74 | private void menuMsgViewClear_Click(object? sender, RoutedEventArgs e) 75 | { 76 | ClearMsg(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/QrcodeView.axaml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/QrcodeView.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Media.Imaging; 3 | using Avalonia.Threading; 4 | 5 | namespace v2rayN.Desktop.Views; 6 | 7 | public partial class QrcodeView : UserControl 8 | { 9 | public QrcodeView() 10 | { 11 | InitializeComponent(); 12 | } 13 | 14 | public QrcodeView(string? url) 15 | { 16 | InitializeComponent(); 17 | 18 | txtContent.Text = url; 19 | imgQrcode.Source = GetQRCode(url); 20 | 21 | txtContent.GotFocus += (_, _) => Dispatcher.UIThread.Post(() => { txtContent.SelectAll(); }); 22 | } 23 | 24 | private Bitmap? GetQRCode(string? url) 25 | { 26 | var bytes = QRCodeHelper.GenQRCode(url); 27 | return ByteToBitmap(bytes); 28 | } 29 | 30 | private Bitmap? ByteToBitmap(byte[]? bytes) 31 | { 32 | if (bytes is null) 33 | { 34 | return null; 35 | } 36 | 37 | using var ms = new MemoryStream(bytes); 38 | return new Bitmap(ms); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia; 3 | using Avalonia.Interactivity; 4 | using Avalonia.ReactiveUI; 5 | using ReactiveUI; 6 | 7 | namespace v2rayN.Desktop.Views; 8 | 9 | public partial class SubEditWindow : ReactiveWindow 10 | { 11 | public SubEditWindow() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | public SubEditWindow(SubItem subItem) 17 | { 18 | InitializeComponent(); 19 | 20 | Loaded += Window_Loaded; 21 | btnCancel.Click += (s, e) => this.Close(); 22 | 23 | ViewModel = new SubEditViewModel(subItem, UpdateViewHandler); 24 | 25 | Global.SubConvertTargets.ForEach(it => 26 | { 27 | cmbConvertTarget.Items.Add(it); 28 | }); 29 | 30 | this.WhenActivated(disposables => 31 | { 32 | this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables); 33 | this.Bind(ViewModel, vm => vm.SelectedSource.Url, v => v.txtUrl.Text).DisposeWith(disposables); 34 | this.Bind(ViewModel, vm => vm.SelectedSource.MoreUrl, v => v.txtMoreUrl.Text).DisposeWith(disposables); 35 | this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnable.IsChecked).DisposeWith(disposables); 36 | this.Bind(ViewModel, vm => vm.SelectedSource.AutoUpdateInterval, v => v.txtAutoUpdateInterval.Text).DisposeWith(disposables); 37 | this.Bind(ViewModel, vm => vm.SelectedSource.UserAgent, v => v.txtUserAgent.Text).DisposeWith(disposables); 38 | this.Bind(ViewModel, vm => vm.SelectedSource.Sort, v => v.txtSort.Text).DisposeWith(disposables); 39 | this.Bind(ViewModel, vm => vm.SelectedSource.Filter, v => v.txtFilter.Text).DisposeWith(disposables); 40 | this.Bind(ViewModel, vm => vm.SelectedSource.ConvertTarget, v => v.cmbConvertTarget.SelectedValue).DisposeWith(disposables); 41 | this.Bind(ViewModel, vm => vm.SelectedSource.PrevProfile, v => v.txtPrevProfile.Text).DisposeWith(disposables); 42 | this.Bind(ViewModel, vm => vm.SelectedSource.NextProfile, v => v.txtNextProfile.Text).DisposeWith(disposables); 43 | this.Bind(ViewModel, vm => vm.SelectedSource.PreSocksPort, v => v.txtPreSocksPort.Text).DisposeWith(disposables); 44 | this.Bind(ViewModel, vm => vm.SelectedSource.Memo, v => v.txtMemo.Text).DisposeWith(disposables); 45 | 46 | this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 47 | }); 48 | } 49 | 50 | private async Task UpdateViewHandler(EViewAction action, object? obj) 51 | { 52 | switch (action) 53 | { 54 | case EViewAction.CloseWindow: 55 | this.Close(true); 56 | break; 57 | } 58 | return await Task.FromResult(true); 59 | } 60 | 61 | private void Window_Loaded(object? sender, RoutedEventArgs e) 62 | { 63 | txtRemarks.Focus(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 18 | 19 | 23 | 67 | 68 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/Views/ThemeSettingView.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using Avalonia; 3 | using Avalonia.ReactiveUI; 4 | using ReactiveUI; 5 | using v2rayN.Desktop.ViewModels; 6 | 7 | namespace v2rayN.Desktop.Views; 8 | 9 | /// 10 | /// ThemeSettingView.xaml 11 | /// 12 | public partial class ThemeSettingView : ReactiveUserControl 13 | { 14 | public ThemeSettingView() 15 | { 16 | InitializeComponent(); 17 | ViewModel = new ThemeSettingViewModel(); 18 | 19 | foreach (ETheme it in Enum.GetValues(typeof(ETheme))) 20 | { 21 | cmbCurrentTheme.Items.Add(it.ToString()); 22 | } 23 | 24 | for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++) 25 | { 26 | cmbCurrentFontSize.Items.Add(i); 27 | } 28 | 29 | Global.Languages.ForEach(it => 30 | { 31 | cmbCurrentLanguage.Items.Add(it); 32 | }); 33 | 34 | this.WhenActivated(disposables => 35 | { 36 | this.Bind(ViewModel, vm => vm.CurrentTheme, v => v.cmbCurrentTheme.SelectedValue).DisposeWith(disposables); 37 | this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.SelectedValue).DisposeWith(disposables); 38 | this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.SelectedValue).DisposeWith(disposables); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | Assets\v2rayN.ico 6 | true 7 | true 8 | v2rayN 9 | 10 | 11 | 12 | 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | true 22 | 23 | 24 | true 25 | 26 | 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Never 41 | 42 | 43 | Always 44 | 45 | 46 | Always 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/v2rayN.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/v2rayN.icns -------------------------------------------------------------------------------- /v2rayN/v2rayN.Desktop/v2rayN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN.Desktop/v2rayN.png -------------------------------------------------------------------------------- /v2rayN/v2rayN/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Windows; 3 | using System.Windows.Threading; 4 | 5 | namespace v2rayN; 6 | 7 | /// 8 | /// Interaction logic for App.xaml 9 | /// 10 | public partial class App : Application 11 | { 12 | public static EventWaitHandle ProgramStarted; 13 | 14 | public App() 15 | { 16 | this.DispatcherUnhandledException += App_DispatcherUnhandledException; 17 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 18 | TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 19 | } 20 | 21 | /// 22 | /// Open only one process 23 | /// 24 | /// 25 | protected override void OnStartup(StartupEventArgs e) 26 | { 27 | var exePathKey = Utils.GetMd5(Utils.GetExePath()); 28 | 29 | var rebootas = (e.Args ?? Array.Empty()).Any(t => t == Global.RebootAs); 30 | ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew); 31 | if (!rebootas && !bCreatedNew) 32 | { 33 | ProgramStarted.Set(); 34 | Environment.Exit(0); 35 | return; 36 | } 37 | 38 | if (!AppHandler.Instance.InitApp()) 39 | { 40 | UI.Show($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用"); 41 | Environment.Exit(0); 42 | return; 43 | } 44 | 45 | AppHandler.Instance.InitComponents(); 46 | base.OnStartup(e); 47 | } 48 | 49 | private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 50 | { 51 | Logging.SaveLog("App_DispatcherUnhandledException", e.Exception); 52 | e.Handled = true; 53 | } 54 | 55 | private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 56 | { 57 | if (e.ExceptionObject != null) 58 | { 59 | Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject); 60 | } 61 | } 62 | 63 | private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) 64 | { 65 | Logging.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception); 66 | } 67 | 68 | protected override void OnExit(ExitEventArgs e) 69 | { 70 | Logging.SaveLog("OnExit"); 71 | base.OnExit(e); 72 | Process.GetCurrentProcess().Kill(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] -------------------------------------------------------------------------------- /v2rayN/v2rayN/Base/MyDGTextColumn.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace v2rayN.Base; 4 | 5 | internal class MyDGTextColumn : DataGridTextColumn 6 | { 7 | public string ExName { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Common/QRCodeHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Drawing; 3 | using System.Windows; 4 | using System.Windows.Interop; 5 | using System.Windows.Media; 6 | using System.Windows.Media.Imaging; 7 | 8 | namespace v2rayN; 9 | 10 | public class QRCodeHelper 11 | { 12 | public static ImageSource? GetQRCode(string? strContent) 13 | { 14 | if (strContent is null) 15 | { 16 | return null; 17 | } 18 | try 19 | { 20 | var qrCodeImage = ServiceLib.Common.QRCodeHelper.GenQRCode(strContent); 21 | return qrCodeImage is null ? null : ByteToImage(qrCodeImage); 22 | } 23 | catch 24 | { 25 | return null; 26 | } 27 | } 28 | 29 | public static byte[]? CaptureScreen(Window window) 30 | { 31 | try 32 | { 33 | GetDpi(window, out var dpiX, out var dpiY); 34 | 35 | var left = (int)(SystemParameters.WorkArea.Left); 36 | var top = (int)(SystemParameters.WorkArea.Top); 37 | var width = (int)(SystemParameters.WorkArea.Width / dpiX); 38 | var height = (int)(SystemParameters.WorkArea.Height / dpiY); 39 | 40 | using var fullImage = new Bitmap(width, height); 41 | using var g = Graphics.FromImage(fullImage); 42 | 43 | g.CopyFromScreen(left, top, 0, 0, fullImage.Size, CopyPixelOperation.SourceCopy); 44 | //fullImage.Save("test1.png", ImageFormat.Png); 45 | return ImageToByte(fullImage); 46 | } 47 | catch 48 | { 49 | return null; 50 | } 51 | } 52 | 53 | private static void GetDpi(Window window, out float x, out float y) 54 | { 55 | var hWnd = new WindowInteropHelper(window).EnsureHandle(); 56 | var g = Graphics.FromHwnd(hWnd); 57 | 58 | x = 96 / g.DpiX; 59 | y = 96 / g.DpiY; 60 | } 61 | 62 | private static ImageSource? ByteToImage(IEnumerable imageData) 63 | { 64 | return new ImageSourceConverter().ConvertFrom(imageData) as BitmapSource; 65 | } 66 | 67 | private static byte[]? ImageToByte(Image img) 68 | { 69 | return new ImageConverter().ConvertTo(img, typeof(byte[])) as byte[]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Common/UI.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using Microsoft.Win32; 3 | 4 | namespace v2rayN; 5 | 6 | internal class UI 7 | { 8 | private static readonly string caption = Global.AppName; 9 | 10 | public static void Show(string msg) 11 | { 12 | MessageBox.Show(msg, caption, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK); 13 | } 14 | 15 | public static MessageBoxResult ShowYesNo(string msg) 16 | { 17 | return MessageBox.Show(msg, caption, MessageBoxButton.YesNo, MessageBoxImage.Question); 18 | } 19 | 20 | public static bool? OpenFileDialog(out string fileName, string filter) 21 | { 22 | fileName = string.Empty; 23 | 24 | var fileDialog = new OpenFileDialog 25 | { 26 | Multiselect = false, 27 | Filter = filter 28 | }; 29 | 30 | if (fileDialog.ShowDialog() != true) 31 | { 32 | return false; 33 | } 34 | fileName = fileDialog.FileName; 35 | 36 | return true; 37 | } 38 | 39 | public static bool? SaveFileDialog(out string fileName, string filter) 40 | { 41 | fileName = string.Empty; 42 | 43 | SaveFileDialog fileDialog = new() 44 | { 45 | Filter = filter, 46 | FilterIndex = 2, 47 | RestoreDirectory = true 48 | }; 49 | if (fileDialog.ShowDialog() != true) 50 | { 51 | return false; 52 | } 53 | 54 | fileName = fileDialog.FileName; 55 | 56 | return true; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Common/WindowsUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 4 | using System.Windows.Interop; 5 | using System.Windows.Media; 6 | using System.Windows.Media.Imaging; 7 | using Microsoft.Win32; 8 | 9 | namespace v2rayN; 10 | 11 | internal static class WindowsUtils 12 | { 13 | private static readonly string _tag = "WindowsUtils"; 14 | 15 | public static string? GetClipboardData() 16 | { 17 | var strData = string.Empty; 18 | try 19 | { 20 | var data = Clipboard.GetDataObject(); 21 | if (data?.GetDataPresent(DataFormats.UnicodeText) == true) 22 | { 23 | strData = data.GetData(DataFormats.UnicodeText)?.ToString(); 24 | } 25 | return strData; 26 | } 27 | catch (Exception ex) 28 | { 29 | Logging.SaveLog(_tag, ex); 30 | } 31 | return strData; 32 | } 33 | 34 | public static void SetClipboardData(string strData) 35 | { 36 | try 37 | { 38 | Clipboard.SetText(strData); 39 | } 40 | catch 41 | { 42 | } 43 | } 44 | 45 | [DllImport("dwmapi.dll")] 46 | public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize); 47 | 48 | public static ImageSource IconToImageSource(Icon icon) 49 | { 50 | return Imaging.CreateBitmapSourceFromHIcon( 51 | icon.Handle, 52 | new System.Windows.Int32Rect(0, 0, icon.Width, icon.Height), 53 | BitmapSizeOptions.FromEmptyOptions()); 54 | } 55 | 56 | public static void SetDarkBorder(Window window, string? theme) 57 | { 58 | var isDark = theme switch 59 | { 60 | nameof(ETheme.Dark) => true, 61 | nameof(ETheme.Light) => false, 62 | _ => IsDarkTheme(), 63 | }; 64 | 65 | SetDarkBorder(window, isDark); 66 | } 67 | 68 | private static void SetDarkBorder(Window window, bool dark) 69 | { 70 | // Make sure the handle is created before the window is shown 71 | IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle(); 72 | int attribute = dark ? 1 : 0; 73 | uint attributeSize = (uint)Marshal.SizeOf(attribute); 74 | DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize); 75 | DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize); 76 | } 77 | 78 | private static bool IsDarkTheme() 79 | { 80 | using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); 81 | var obj = key?.GetValue("AppsUseLightTheme"); 82 | int.TryParse(obj?.ToString(), out var value); 83 | return value == 0; 84 | } 85 | 86 | #region Windows API 87 | 88 | [Flags] 89 | public enum DWMWINDOWATTRIBUTE : uint 90 | { 91 | DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, 92 | DWMWA_USE_IMMERSIVE_DARK_MODE = 20, 93 | } 94 | 95 | #endregion Windows API 96 | } 97 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Converters/DelayColorConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Data; 2 | using System.Windows.Media; 3 | 4 | namespace v2rayN.Converters; 5 | 6 | public class DelayColorConverter : IValueConverter 7 | { 8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 9 | { 10 | int.TryParse(value.ToString(), out var delay); 11 | 12 | if (delay <= 0) 13 | return new SolidColorBrush(Colors.Red); 14 | if (delay <= 500) 15 | return new SolidColorBrush(Colors.Green); 16 | else 17 | return new SolidColorBrush(Colors.IndianRed); 18 | } 19 | 20 | public object? ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 21 | { 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Converters/InverseBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Windows.Data; 3 | 4 | namespace v2rayN.Converters; 5 | 6 | [ValueConversion(typeof(bool), typeof(bool))] 7 | public class InverseBooleanConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | if (targetType != typeof(bool)) 12 | { 13 | throw new InvalidOperationException("The target must be a boolean"); 14 | } 15 | 16 | return !(bool)value; 17 | } 18 | 19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Converters/MaterialDesignFonts.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Media; 2 | 3 | namespace v2rayN.Converters; 4 | 5 | public class MaterialDesignFonts 6 | { 7 | public static FontFamily MyFont { get; } 8 | 9 | static MaterialDesignFonts() 10 | { 11 | try 12 | { 13 | var fontFamily = AppHandler.Instance.Config.UiItem.CurrentFontFamily; 14 | if (fontFamily.IsNotEmpty()) 15 | { 16 | var fontPath = Utils.GetFontsPath(); 17 | MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}"); 18 | } 19 | } 20 | catch 21 | { 22 | } 23 | MyFont ??= new FontFamily("Microsoft YaHei"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using ServiceLib; 2 | global using ServiceLib.Base; 3 | global using ServiceLib.Common; 4 | global using ServiceLib.Enums; 5 | global using ServiceLib.Handler; 6 | global using ServiceLib.Models; 7 | global using ServiceLib.Resx; 8 | global using ServiceLib.ViewModels; -------------------------------------------------------------------------------- /v2rayN/v2rayN/Resources/NotifyIcon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN/Resources/NotifyIcon1.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN/Resources/NotifyIcon2.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN/Resources/NotifyIcon2.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN/Resources/NotifyIcon3.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN/Resources/NotifyIcon3.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN/Resources/NotifyIcon4.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN/Resources/NotifyIcon4.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN/Resources/v2rayN.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2dust/v2rayN/87f7e650762a4cddcb9f51d23795e0ed7bcd8315/v2rayN/v2rayN/Resources/v2rayN.ico -------------------------------------------------------------------------------- /v2rayN/v2rayN/Views/AddServer2Window.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using System.Windows; 3 | using ReactiveUI; 4 | 5 | namespace v2rayN.Views; 6 | 7 | public partial class AddServer2Window 8 | { 9 | public AddServer2Window(ProfileItem profileItem) 10 | { 11 | InitializeComponent(); 12 | 13 | this.Owner = Application.Current.MainWindow; 14 | this.Loaded += Window_Loaded; 15 | ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler); 16 | 17 | foreach (ECoreType it in Enum.GetValues(typeof(ECoreType))) 18 | { 19 | if (it == ECoreType.v2rayN) 20 | continue; 21 | cmbCoreType.Items.Add(it.ToString()); 22 | } 23 | cmbCoreType.Items.Add(string.Empty); 24 | 25 | this.WhenActivated(disposables => 26 | { 27 | this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables); 28 | this.Bind(ViewModel, vm => vm.SelectedSource.Address, v => v.txtAddress.Text).DisposeWith(disposables); 29 | this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables); 30 | this.Bind(ViewModel, vm => vm.SelectedSource.DisplayLog, v => v.togDisplayLog.IsChecked).DisposeWith(disposables); 31 | this.Bind(ViewModel, vm => vm.SelectedSource.PreSocksPort, v => v.txtPreSocksPort.Text).DisposeWith(disposables); 32 | 33 | this.BindCommand(ViewModel, vm => vm.BrowseServerCmd, v => v.btnBrowse).DisposeWith(disposables); 34 | this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables); 35 | this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables); 36 | }); 37 | WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); 38 | } 39 | 40 | private async Task UpdateViewHandler(EViewAction action, object? obj) 41 | { 42 | switch (action) 43 | { 44 | case EViewAction.CloseWindow: 45 | this.DialogResult = true; 46 | break; 47 | 48 | case EViewAction.BrowseServer: 49 | if (UI.OpenFileDialog(out string fileName, "Config|*.json|YAML|*.yaml;*.yml|All|*.*") != true) 50 | { 51 | return false; 52 | } 53 | ViewModel?.BrowseServer(fileName); 54 | break; 55 | } 56 | 57 | return await Task.FromResult(true); 58 | } 59 | 60 | private void Window_Loaded(object sender, RoutedEventArgs e) 61 | { 62 | txtRemarks.Focus(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Views/BackupAndRestoreView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using System.Windows; 3 | using ReactiveUI; 4 | 5 | namespace v2rayN.Views; 6 | 7 | public partial class BackupAndRestoreView 8 | { 9 | public BackupAndRestoreView() 10 | { 11 | InitializeComponent(); 12 | menuLocalBackup.Click += MenuLocalBackup_Click; 13 | menuLocalRestore.Click += MenuLocalRestore_Click; 14 | 15 | ViewModel = new BackupAndRestoreViewModel(UpdateViewHandler); 16 | 17 | this.WhenActivated(disposables => 18 | { 19 | this.Bind(ViewModel, vm => vm.OperationMsg, v => v.txtMsg.Text).DisposeWith(disposables); 20 | 21 | this.Bind(ViewModel, vm => vm.SelectedSource.Url, v => v.txtWebDavUrl.Text).DisposeWith(disposables); 22 | this.Bind(ViewModel, vm => vm.SelectedSource.UserName, v => v.txtWebDavUserName.Text).DisposeWith(disposables); 23 | this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtWebDavPassword.Text).DisposeWith(disposables); 24 | this.Bind(ViewModel, vm => vm.SelectedSource.DirName, v => v.txtWebDavDirName.Text).DisposeWith(disposables); 25 | 26 | this.BindCommand(ViewModel, vm => vm.WebDavCheckCmd, v => v.menuWebDavCheck).DisposeWith(disposables); 27 | 28 | this.BindCommand(ViewModel, vm => vm.RemoteBackupCmd, v => v.menuRemoteBackup).DisposeWith(disposables); 29 | this.BindCommand(ViewModel, vm => vm.RemoteRestoreCmd, v => v.menuRemoteRestore).DisposeWith(disposables); 30 | }); 31 | } 32 | 33 | private void MenuLocalBackup_Click(object sender, RoutedEventArgs e) 34 | { 35 | if (UI.SaveFileDialog(out string fileName, "Zip|*.zip") != true) 36 | { 37 | return; 38 | } 39 | ViewModel?.LocalBackup(fileName); 40 | } 41 | 42 | private void MenuLocalRestore_Click(object sender, RoutedEventArgs e) 43 | { 44 | if (UI.OpenFileDialog(out string fileName, "Zip|*.zip|All|*.*") != true) 45 | { 46 | return; 47 | } 48 | ViewModel?.LocalRestore(fileName); 49 | } 50 | 51 | private async Task UpdateViewHandler(EViewAction action, object? obj) 52 | { 53 | return await Task.FromResult(true); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Views/CheckUpdateView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using System.Windows; 3 | using System.Windows.Threading; 4 | using ReactiveUI; 5 | 6 | namespace v2rayN.Views; 7 | 8 | public partial class CheckUpdateView 9 | { 10 | public CheckUpdateView() 11 | { 12 | InitializeComponent(); 13 | 14 | ViewModel = new CheckUpdateViewModel(UpdateViewHandler); 15 | 16 | this.WhenActivated(disposables => 17 | { 18 | this.OneWayBind(ViewModel, vm => vm.CheckUpdateModels, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables); 19 | 20 | this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables); 21 | this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdate).DisposeWith(disposables); 22 | }); 23 | } 24 | 25 | private async Task UpdateViewHandler(EViewAction action, object? obj) 26 | { 27 | switch (action) 28 | { 29 | case EViewAction.DispatcherCheckUpdate: 30 | if (obj is null) 31 | return false; 32 | Application.Current?.Dispatcher.Invoke((() => 33 | { 34 | ViewModel?.UpdateViewResult((CheckUpdateModel)obj); 35 | }), DispatcherPriority.Normal); 36 | break; 37 | 38 | case EViewAction.DispatcherCheckUpdateFinished: 39 | if (obj is null) 40 | return false; 41 | Application.Current?.Dispatcher.Invoke((() => 42 | { 43 | ViewModel?.UpdateFinishedResult((bool)obj); 44 | }), DispatcherPriority.Normal); 45 | break; 46 | } 47 | 48 | return await Task.FromResult(true); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Views/ClashConnectionsView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | using System.Windows.Threading; 5 | using ReactiveUI; 6 | 7 | namespace v2rayN.Views; 8 | 9 | /// 10 | /// Interaction logic for ConnectionsView.xaml 11 | /// 12 | public partial class ClashConnectionsView 13 | { 14 | public ClashConnectionsView() 15 | { 16 | InitializeComponent(); 17 | ViewModel = new ClashConnectionsViewModel(UpdateViewHandler); 18 | btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click; 19 | 20 | this.WhenActivated(disposables => 21 | { 22 | this.OneWayBind(ViewModel, vm => vm.ConnectionItems, v => v.lstConnections.ItemsSource).DisposeWith(disposables); 23 | this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstConnections.SelectedItem).DisposeWith(disposables); 24 | 25 | this.BindCommand(ViewModel, vm => vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables); 26 | this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables); 27 | 28 | this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables); 29 | this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables); 30 | this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables); 31 | }); 32 | } 33 | 34 | private async Task UpdateViewHandler(EViewAction action, object? obj) 35 | { 36 | switch (action) 37 | { 38 | case EViewAction.DispatcherRefreshConnections: 39 | if (obj is null) 40 | return false; 41 | Application.Current?.Dispatcher.Invoke((() => 42 | { 43 | ViewModel?.RefreshConnections((List?)obj); 44 | }), DispatcherPriority.Normal); 45 | break; 46 | } 47 | 48 | return await Task.FromResult(true); 49 | } 50 | 51 | private void BtnAutofitColumnWidth_Click(object sender, RoutedEventArgs e) 52 | { 53 | AutofitColumnWidth(); 54 | } 55 | 56 | private void AutofitColumnWidth() 57 | { 58 | try 59 | { 60 | foreach (var it in lstConnections.Columns) 61 | { 62 | it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); 63 | } 64 | } 65 | catch (Exception ex) 66 | { 67 | Logging.SaveLog("ClashConnectionsView", ex); 68 | } 69 | } 70 | 71 | private void btnClose_Click(object sender, System.Windows.RoutedEventArgs e) 72 | { 73 | ViewModel?.ClashConnectionClose(false); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using System.Windows; 3 | using ReactiveUI; 4 | 5 | namespace v2rayN.Views; 6 | 7 | public partial class DNSSettingWindow 8 | { 9 | private static Config _config; 10 | 11 | public DNSSettingWindow() 12 | { 13 | InitializeComponent(); 14 | 15 | this.Owner = Application.Current.MainWindow; 16 | _config = AppHandler.Instance.Config; 17 | 18 | ViewModel = new DNSSettingViewModel(UpdateViewHandler); 19 | 20 | Global.DomainStrategy4Freedoms.ForEach(it => 21 | { 22 | cmbdomainStrategy4Freedom.Items.Add(it); 23 | }); 24 | Global.SingboxDomainStrategy4Out.ForEach(it => 25 | { 26 | cmbdomainStrategy4Out.Items.Add(it); 27 | }); 28 | Global.DomainDNSAddress.ForEach(it => 29 | { 30 | cmbdomainDNSAddress.Items.Add(it); 31 | }); 32 | Global.SingboxDomainDNSAddress.ForEach(it => 33 | { 34 | cmbdomainDNSAddress2.Items.Add(it); 35 | }); 36 | 37 | this.WhenActivated(disposables => 38 | { 39 | this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables); 40 | this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.Text).DisposeWith(disposables); 41 | this.Bind(ViewModel, vm => vm.DomainDNSAddress, v => v.cmbdomainDNSAddress.Text).DisposeWith(disposables); 42 | this.Bind(ViewModel, vm => vm.NormalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables); 43 | 44 | this.Bind(ViewModel, vm => vm.DomainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.Text).DisposeWith(disposables); 45 | this.Bind(ViewModel, vm => vm.DomainDNSAddress2, v => v.cmbdomainDNSAddress2.Text).DisposeWith(disposables); 46 | this.Bind(ViewModel, vm => vm.NormalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables); 47 | this.Bind(ViewModel, vm => vm.TunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables); 48 | 49 | this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 50 | this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables); 51 | this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables); 52 | }); 53 | WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); 54 | } 55 | 56 | private async Task UpdateViewHandler(EViewAction action, object? obj) 57 | { 58 | switch (action) 59 | { 60 | case EViewAction.CloseWindow: 61 | this.DialogResult = true; 62 | break; 63 | } 64 | return await Task.FromResult(true); 65 | } 66 | 67 | private void linkDnsObjectDoc_Click(object sender, RoutedEventArgs e) 68 | { 69 | ProcUtils.ProcessStart("https://xtls.github.io/config/dns.html#dnsobject"); 70 | } 71 | 72 | private void linkDnsSingboxObjectDoc_Click(object sender, RoutedEventArgs e) 73 | { 74 | ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/"); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Views/MsgView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reactive.Disposables; 2 | using System.Windows; 3 | using System.Windows.Threading; 4 | using ReactiveUI; 5 | 6 | namespace v2rayN.Views; 7 | 8 | public partial class MsgView 9 | { 10 | public MsgView() 11 | { 12 | InitializeComponent(); 13 | 14 | ViewModel = new MsgViewModel(UpdateViewHandler); 15 | 16 | this.WhenActivated(disposables => 17 | { 18 | this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables); 19 | this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables); 20 | }); 21 | 22 | btnCopy.Click += menuMsgViewCopyAll_Click; 23 | btnClear.Click += menuMsgViewClear_Click; 24 | menuMsgViewSelectAll.Click += menuMsgViewSelectAll_Click; 25 | menuMsgViewCopy.Click += menuMsgViewCopy_Click; 26 | menuMsgViewCopyAll.Click += menuMsgViewCopyAll_Click; 27 | menuMsgViewClear.Click += menuMsgViewClear_Click; 28 | 29 | Global.PresetMsgFilters.ForEach(it => 30 | { 31 | cmbMsgFilter.Items.Add(it); 32 | }); 33 | } 34 | 35 | private async Task UpdateViewHandler(EViewAction action, object? obj) 36 | { 37 | switch (action) 38 | { 39 | case EViewAction.DispatcherShowMsg: 40 | if (obj is null) 41 | return false; 42 | Application.Current?.Dispatcher.Invoke((() => 43 | { 44 | ShowMsg(obj); 45 | }), DispatcherPriority.ApplicationIdle); 46 | break; 47 | } 48 | return await Task.FromResult(true); 49 | } 50 | 51 | private void ShowMsg(object msg) 52 | { 53 | txtMsg.BeginChange(); 54 | txtMsg.Text = msg.ToString(); 55 | if (togScrollToEnd.IsChecked ?? true) 56 | { 57 | txtMsg.ScrollToEnd(); 58 | } 59 | txtMsg.EndChange(); 60 | } 61 | 62 | public void ClearMsg() 63 | { 64 | ViewModel?.ClearMsg(); 65 | txtMsg.Clear(); 66 | } 67 | 68 | private void menuMsgViewSelectAll_Click(object sender, System.Windows.RoutedEventArgs e) 69 | { 70 | txtMsg.Focus(); 71 | txtMsg.SelectAll(); 72 | } 73 | 74 | private void menuMsgViewCopy_Click(object sender, System.Windows.RoutedEventArgs e) 75 | { 76 | var data = txtMsg.SelectedText.TrimEx(); 77 | WindowsUtils.SetClipboardData(data); 78 | } 79 | 80 | private void menuMsgViewCopyAll_Click(object sender, System.Windows.RoutedEventArgs e) 81 | { 82 | var data = txtMsg.Text; 83 | WindowsUtils.SetClipboardData(data); 84 | } 85 | 86 | private void menuMsgViewClear_Click(object sender, System.Windows.RoutedEventArgs e) 87 | { 88 | ClearMsg(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /v2rayN/v2rayN/Views/QrcodeView.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 37 | 38 |