mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-02 10:35:00 +03:00
Native Aot (#10295)
* Protect models * Json Context * YAML AOT-friendly optimization * Run the Test in AOT mode * Remove TaskScheduler * Clean build output * Workflows
This commit is contained in:
@@ -29,6 +29,22 @@ jobs:
|
|||||||
release_tag: ${{ inputs.release_tag }}
|
release_tag: ${{ inputs.release_tag }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
build-aot:
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
with:
|
||||||
|
target: linux
|
||||||
|
isAot: true
|
||||||
|
|
||||||
|
release-aot-zip:
|
||||||
|
if: inputs.release_tag != ''
|
||||||
|
needs: build-aot
|
||||||
|
uses: ./.github/workflows/package-zip.yml
|
||||||
|
with:
|
||||||
|
target: linux
|
||||||
|
release_tag: ${{ inputs.release_tag }}
|
||||||
|
isAot: true
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
deb:
|
deb:
|
||||||
name: build and release deb x64 & arm64
|
name: build and release deb x64 & arm64
|
||||||
if: (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
if: (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
||||||
|
|||||||
@@ -29,6 +29,22 @@ jobs:
|
|||||||
release_tag: ${{ inputs.release_tag }}
|
release_tag: ${{ inputs.release_tag }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
build-aot:
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
with:
|
||||||
|
target: macos
|
||||||
|
isAot: true
|
||||||
|
|
||||||
|
release-aot-zip:
|
||||||
|
if: inputs.release_tag != ''
|
||||||
|
needs: build-aot
|
||||||
|
uses: ./.github/workflows/package-zip.yml
|
||||||
|
with:
|
||||||
|
target: macos
|
||||||
|
release_tag: ${{ inputs.release_tag }}
|
||||||
|
isAot: true
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
dmg:
|
dmg:
|
||||||
name: package and release macOS dmg
|
name: package and release macOS dmg
|
||||||
if: inputs.release_tag != ''
|
if: inputs.release_tag != ''
|
||||||
|
|||||||
@@ -28,3 +28,19 @@ jobs:
|
|||||||
target: windows-desktop
|
target: windows-desktop
|
||||||
release_tag: ${{ inputs.release_tag }}
|
release_tag: ${{ inputs.release_tag }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
build-aot:
|
||||||
|
uses: ./.github/workflows/build.yml
|
||||||
|
with:
|
||||||
|
target: windows
|
||||||
|
isAot: true
|
||||||
|
|
||||||
|
release-aot-zip:
|
||||||
|
if: inputs.release_tag != ''
|
||||||
|
needs: build-aot
|
||||||
|
uses: ./.github/workflows/package-zip.yml
|
||||||
|
with:
|
||||||
|
target: windows-desktop
|
||||||
|
release_tag: ${{ inputs.release_tag }}
|
||||||
|
isAot: true
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
default: './v2rayN.Desktop/v2rayN.Desktop.csproj'
|
default: './v2rayN.Desktop/v2rayN.Desktop.csproj'
|
||||||
|
isAot:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -27,7 +31,6 @@ jobs:
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
env:
|
env:
|
||||||
Output: "${{ github.workspace }}/${{ matrix.arch }}"
|
|
||||||
RID: |-
|
RID: |-
|
||||||
${{
|
${{
|
||||||
case(
|
case(
|
||||||
@@ -41,6 +44,7 @@ jobs:
|
|||||||
${{
|
${{
|
||||||
case(
|
case(
|
||||||
inputs.target == 'windows', '-p:EnableWindowsTargeting=true',
|
inputs.target == 'windows', '-p:EnableWindowsTargeting=true',
|
||||||
|
inputs.target == 'linux', (matrix.arch == 'arm64' && '-p:LinkerFlavor=lld -p:ObjCopyName=llvm-objcopy' || ''),
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
@@ -71,25 +75,65 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v6
|
uses: actions/setup-dotnet@v6
|
||||||
with:
|
with:
|
||||||
dotnet-version: 10.0.1xx
|
dotnet-version: 10.0.x
|
||||||
|
|
||||||
- name: Build v2rayN
|
- name: Install dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ./v2rayN
|
if: inputs.target == 'linux' && inputs.isAot
|
||||||
run: dotnet publish $Project -c Release -r $RID -p:SelfContained=true $ExtOpt -o $Output
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y clang zlib1g-dev build-essential
|
||||||
|
|
||||||
|
- name: Install dependencies cross-arch
|
||||||
|
shell: bash
|
||||||
|
if: inputs.target == 'linux' && inputs.isAot && matrix.arch == 'arm64'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y lld llvm binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||||
|
|
||||||
|
- name: Set AOT Environment Variable
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [ "${{ inputs.isAot }}" = "true" ]; then
|
||||||
|
echo "DOTNET_AOT_ARG=-p:IsAot=true" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "DOTNET_AOT_ARG=-p:IsAot=false" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Set OUTPUT Environment Variable
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
RAW_PATH="${{ github.workspace }}/${{ matrix.arch }}${{ inputs.isAot && '-aot' || '' }}"
|
||||||
|
echo "OUTPUT=${RAW_PATH//\\//}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Build AmazTool
|
- name: Build AmazTool
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: ./v2rayN
|
working-directory: ./v2rayN
|
||||||
run: dotnet publish ./AmazTool/AmazTool.csproj -c Release -r $RID -p:SelfContained=true -p:PublishTrimmed=true $ExtOpt -o $Output
|
run: dotnet publish ./AmazTool/AmazTool.csproj -c Release -r $RID -p:SelfContained=true -p:PublishTrimmed=true $ExtOpt ${{ env.DOTNET_AOT_ARG }} -o ${{ env.OUTPUT }}
|
||||||
|
|
||||||
|
- name: Build v2rayN WPF
|
||||||
|
shell: bash
|
||||||
|
if: inputs.project == './v2rayN/v2rayN.csproj'
|
||||||
|
working-directory: ./v2rayN
|
||||||
|
run: dotnet publish $Project -c Release -r $RID -p:SelfContained=true $ExtOpt -o ${{ env.OUTPUT }}
|
||||||
|
|
||||||
|
- name: Build v2rayN Avalonia
|
||||||
|
shell: bash
|
||||||
|
if: inputs.project == './v2rayN.Desktop/v2rayN.Desktop.csproj'
|
||||||
|
working-directory: ./v2rayN
|
||||||
|
run: dotnet publish $Project -c Release -r $RID -p:SelfContained=true $ExtOpt ${{ env.DOTNET_AOT_ARG }} -o ${{ env.OUTPUT }}
|
||||||
|
|
||||||
- name: Remove Debug Symbols
|
- name: Remove Debug Symbols
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
find ${{ matrix.arch }} -type f -name '*.pdb' -delete
|
find ${{ env.OUTPUT }} -type f -name '*.pdb' -delete
|
||||||
|
find ${{ env.OUTPUT }} -type f -name '*.debug' -delete
|
||||||
|
find ${{ env.OUTPUT }} -type f -name '*.dbg' -delete
|
||||||
|
find ${{ env.OUTPUT }} -type f -name '*.sym' -delete
|
||||||
|
find ${{ env.OUTPUT }} -name '*.dSYM' -exec rm -rf {} +
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.arch }}
|
name: ${{ matrix.arch }}${{ inputs.isAot && '-aot' || '' }}
|
||||||
path: ${{ matrix.arch }}
|
path: ${{ env.OUTPUT }}
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ on:
|
|||||||
target: # windows linux macos windows-desktop
|
target: # windows linux macos windows-desktop
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
isAot:
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
secrets:
|
secrets:
|
||||||
GPG_PRIVATE_KEY:
|
GPG_PRIVATE_KEY:
|
||||||
required: true
|
required: true
|
||||||
@@ -43,27 +47,62 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Set package variables
|
||||||
|
id: package-vars
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
INPUT_TARGET: ${{ inputs.target }}
|
||||||
|
INPUT_IS_AOT: ${{ inputs.isAot }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
package_dir="v2rayN-${Target}-${Arch}"
|
||||||
|
package_file="${package_dir}.zip"
|
||||||
|
build_artifact_name="${{ matrix.arch }}"
|
||||||
|
rename_suffix=""
|
||||||
|
if [[ "$INPUT_IS_AOT" == "true" ]]; then
|
||||||
|
build_artifact_name="${build_artifact_name}-aot"
|
||||||
|
rename_suffix="-aot"
|
||||||
|
fi
|
||||||
|
if [[ "$INPUT_TARGET" == "windows-desktop" ]]; then
|
||||||
|
rename_suffix="-desktop${rename_suffix}"
|
||||||
|
fi
|
||||||
|
final_package_file="${package_dir}${rename_suffix}.zip"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "build_artifact_name=${build_artifact_name}"
|
||||||
|
echo "package_dir=${package_dir}"
|
||||||
|
echo "package_file=${package_file}"
|
||||||
|
echo "final_package_file=${final_package_file}"
|
||||||
|
echo "rename_suffix=${rename_suffix}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Restore build artifacts
|
- name: Restore build artifacts
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.arch }}
|
name: ${{ steps.package-vars.outputs.build_artifact_name }}
|
||||||
path: v2rayN-${{ env.Target }}-${{ env.Arch }}
|
path: ${{ steps.package-vars.outputs.package_dir }}
|
||||||
|
|
||||||
- name: Get v2rayN-core-bin
|
- name: Get v2rayN-core-bin
|
||||||
run: wget -nv -O v2rayN-$Target-$Arch.zip "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/v2rayN-$Target-$Arch.zip"
|
run: |
|
||||||
|
wget -nv -O "${{ steps.package-vars.outputs.package_file }}" "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/v2rayN-$Target-$Arch.zip"
|
||||||
|
|
||||||
- name: Package zip archive
|
- name: Package zip archive
|
||||||
run: 7z a -tZip v2rayN-$Target-$Arch.zip v2rayN-$Target-$Arch -mx1
|
shell: bash
|
||||||
|
run: |
|
||||||
|
7z a -tZip "${{ steps.package-vars.outputs.package_file }}" "${{ steps.package-vars.outputs.package_dir }}" -mx1
|
||||||
|
|
||||||
- name: Rename windows-desktop
|
- name: Rename package archive
|
||||||
if: inputs.target == 'windows-desktop'
|
if: steps.package-vars.outputs.rename_suffix != ''
|
||||||
run: mv "v2rayN-$Target-$Arch.zip" "v2rayN-$Target-$Arch-desktop.zip"
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mv "${{ steps.package-vars.outputs.package_file }}" \
|
||||||
|
"${{ steps.package-vars.outputs.package_dir }}${{ steps.package-vars.outputs.rename_suffix }}.zip"
|
||||||
|
|
||||||
- name: Upload zip artifact
|
- name: Upload zip artifact
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: release-${{ inputs.target }}-${{ matrix.arch }}
|
name: release-${{ inputs.target }}-${{ matrix.arch }}${{ inputs.isAot && '-aot' || '' }}
|
||||||
path: v2rayN*.zip
|
path: ${{ steps.package-vars.outputs.final_package_file }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
release:
|
release:
|
||||||
@@ -75,7 +114,7 @@ jobs:
|
|||||||
uses: ./.github/workflows/upload-sign.yml
|
uses: ./.github/workflows/upload-sign.yml
|
||||||
with:
|
with:
|
||||||
release_tag: ${{ inputs.release_tag }}
|
release_tag: ${{ inputs.release_tag }}
|
||||||
artifact_name: release-${{ inputs.target }}-${{ matrix.arch }}
|
artifact_name: release-${{ inputs.target }}-${{ matrix.arch }}${{ inputs.isAot && '-aot' || '' }}
|
||||||
file_pattern: '*.zip'
|
file_pattern: '*.zip'
|
||||||
secrets:
|
secrets:
|
||||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
|
|||||||
@@ -5,16 +5,31 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Update="Resx\Resource.resx">
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
|
||||||
</EmbeddedResource>
|
|
||||||
|
|
||||||
<Compile Update="Resx\Resource.Designer.cs">
|
<Compile Update="Resx\Resource.Designer.cs">
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DependentUpon>Resource.resx</DependentUpon>
|
<DependentUpon>Resource.resx</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<EmbeddedResource Update="Resx\Resource.resx">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Update="Resx\ResUI.zh-Hans.resx">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Update="Resx\ResUI.zh-Hant.resx">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="RemoveAotSatelliteOutputs" AfterTargets="ComputeFilesToPublish" Condition="'$(PublishAot)' == 'true'">
|
||||||
|
<ItemGroup>
|
||||||
|
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)"
|
||||||
|
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Contains('resources.dll'))" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
+1
-1
@@ -19,7 +19,7 @@ namespace AmazTool.Resx {
|
|||||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Resource {
|
internal class Resource {
|
||||||
|
|||||||
@@ -29,4 +29,14 @@
|
|||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<PublishReadyToRun>false</PublishReadyToRun>
|
<PublishReadyToRun>false</PublishReadyToRun>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<IsAot Condition="'$(IsAot)' == ''">false</IsAot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(IsAot)' == 'true'">
|
||||||
|
<PublishAot>true</PublishAot>
|
||||||
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
|
<DefineConstants>$(DefineConstants);V2RAYN_IS_AOT</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -25,8 +25,7 @@
|
|||||||
<PackageVersion Include="NLog" Version="6.2.1" />
|
<PackageVersion Include="NLog" Version="6.2.1" />
|
||||||
<PackageVersion Include="sqlite-net-e" Version="1.11.285" />
|
<PackageVersion Include="sqlite-net-e" Version="1.11.285" />
|
||||||
<PackageVersion Include="Repobot.SQLite.Unofficial" Version="3.53.4.1" />
|
<PackageVersion Include="Repobot.SQLite.Unofficial" Version="3.53.4.1" />
|
||||||
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
<PackageVersion Include="TUnit" Version="1.73.19" />
|
||||||
<PackageVersion Include="TUnit" Version="1.75.0" />
|
|
||||||
<PackageVersion Include="TUnit.Assertions.Should" Version="1.72.16-beta" />
|
<PackageVersion Include="TUnit.Assertions.Should" Version="1.72.16-beta" />
|
||||||
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
<PackageVersion Include="WebDav.Client" Version="2.9.0" />
|
||||||
<PackageVersion Include="YamlDotNet" Version="18.1.0" />
|
<PackageVersion Include="YamlDotNet" Version="18.1.0" />
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<PublishAot>true</PublishAot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -7,40 +7,45 @@ public class JsonUtils
|
|||||||
private static readonly JsonSerializerOptions _defaultDeserializeOptions = new()
|
private static readonly JsonSerializerOptions _defaultDeserializeOptions = new()
|
||||||
{
|
{
|
||||||
PropertyNameCaseInsensitive = true,
|
PropertyNameCaseInsensitive = true,
|
||||||
ReadCommentHandling = JsonCommentHandling.Skip
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||||
|
TypeInfoResolver = AppJsonContext.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions _defaultSerializeOptions = new()
|
private static readonly JsonSerializerOptions _defaultSerializeOptions = new()
|
||||||
{
|
{
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
TypeInfoResolver = AppJsonContext.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions _defaultSerializeNoIndentedOptions = new()
|
private static readonly JsonSerializerOptions _defaultSerializeNoIndentedOptions = new()
|
||||||
{
|
{
|
||||||
WriteIndented = false,
|
WriteIndented = false,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
TypeInfoResolver = AppJsonContext.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions _nullValueSerializeOptions = new()
|
private static readonly JsonSerializerOptions _nullValueSerializeOptions = new()
|
||||||
{
|
{
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
TypeInfoResolver = AppJsonContext.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions _nullValueSerializeNoIndentedOptions = new()
|
private static readonly JsonSerializerOptions _nullValueSerializeNoIndentedOptions = new()
|
||||||
{
|
{
|
||||||
WriteIndented = false,
|
WriteIndented = false,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
TypeInfoResolver = AppJsonContext.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly JsonDocumentOptions _defaultDocumentOptions = new()
|
private static readonly JsonDocumentOptions _defaultDocumentOptions = new()
|
||||||
{
|
{
|
||||||
CommentHandling = JsonCommentHandling.Skip
|
CommentHandling = JsonCommentHandling.Skip,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -109,7 +114,7 @@ public class JsonUtils
|
|||||||
/// <param name="indented"></param>
|
/// <param name="indented"></param>
|
||||||
/// <param name="nullValue"></param>
|
/// <param name="nullValue"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string Serialize(object? obj, bool indented = true, bool nullValue = false)
|
public static string Serialize<T>(T? obj, bool indented = true, bool nullValue = false)
|
||||||
{
|
{
|
||||||
var result = string.Empty;
|
var result = string.Empty;
|
||||||
try
|
try
|
||||||
@@ -140,7 +145,7 @@ public class JsonUtils
|
|||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string Serialize(object? obj, JsonSerializerOptions? options)
|
public static string SerializeCamelCase<T>(T? obj)
|
||||||
{
|
{
|
||||||
var result = string.Empty;
|
var result = string.Empty;
|
||||||
try
|
try
|
||||||
@@ -149,7 +154,14 @@ public class JsonUtils
|
|||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result = JsonSerializer.Serialize(obj, options ?? _defaultSerializeOptions);
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
TypeInfoResolver = AppJsonContext.Default,
|
||||||
|
};
|
||||||
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -162,9 +174,108 @@ public class JsonUtils
|
|||||||
/// SerializeToNode
|
/// SerializeToNode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="nullValue"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static JsonNode? SerializeToNode(object? obj, JsonSerializerOptions? options = null)
|
public static JsonNode? SerializeToNode<T>(T? obj, bool nullValue = false)
|
||||||
{
|
{
|
||||||
|
var options = nullValue ? _nullValueSerializeOptions : _defaultSerializeOptions;
|
||||||
return JsonSerializer.SerializeToNode(obj, options);
|
return JsonSerializer.SerializeToNode(obj, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static JsonArray? SerializeToArray(IEnumerable<string>? values)
|
||||||
|
{
|
||||||
|
if (values is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var array = new JsonArray();
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
var valueNode = JsonSerializer.SerializeToNode(value, _defaultSerializeOptions);
|
||||||
|
array.Add(valueNode);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(Config))]
|
||||||
|
[JsonSerializable(typeof(RulesItem))]
|
||||||
|
[JsonSerializable(typeof(ProfileItem))]
|
||||||
|
[JsonSerializable(typeof(List<RulesItem>))]
|
||||||
|
[JsonSerializable(typeof(List<ProfileItem>))]
|
||||||
|
[JsonSerializable(typeof(ProfileItemModel))]
|
||||||
|
[JsonSerializable(typeof(List<ProfileItemModel>))]
|
||||||
|
[JsonSerializable(typeof(RoutingTemplate))]
|
||||||
|
[JsonSerializable(typeof(DNSItem))]
|
||||||
|
[JsonSerializable(typeof(SimpleDNSItem))]
|
||||||
|
[JsonSerializable(typeof(IPAPIInfo))]
|
||||||
|
[JsonSerializable(typeof(SsSIP008))]
|
||||||
|
[JsonSerializable(typeof(List<SsServer>))]
|
||||||
|
[JsonSerializable(typeof(SsServer))]
|
||||||
|
[JsonSerializable(typeof(VmessQRCode))]
|
||||||
|
[JsonSerializable(typeof(ClashProxies))]
|
||||||
|
[JsonSerializable(typeof(ClashProviders))]
|
||||||
|
[JsonSerializable(typeof(ClashConnections))]
|
||||||
|
[JsonSerializable(typeof(ProtocolExtraItem))]
|
||||||
|
[JsonSerializable(typeof(TransportExtraItem))]
|
||||||
|
[JsonSerializable(typeof(TrafficItem))]
|
||||||
|
[JsonSerializable(typeof(V2rayMetricsVars))]
|
||||||
|
[JsonSerializable(typeof(V2rayMetricsVarsLink))]
|
||||||
|
[JsonSerializable(typeof(GitHubRelease))]
|
||||||
|
[JsonSerializable(typeof(List<GitHubRelease>))]
|
||||||
|
[JsonSerializable(typeof(ServerStatItem))]
|
||||||
|
[JsonSerializable(typeof(WebDavItem))]
|
||||||
|
[JsonSerializable(typeof(KeyEventItem))]
|
||||||
|
[JsonSerializable(typeof(SubItem))]
|
||||||
|
[JsonSerializable(typeof(SingboxConfig))]
|
||||||
|
[JsonSerializable(typeof(Dns4Sbox))]
|
||||||
|
[JsonSerializable(typeof(Inbound4Sbox))]
|
||||||
|
[JsonSerializable(typeof(List<Inbound4Sbox>))]
|
||||||
|
[JsonSerializable(typeof(Endpoints4Sbox))]
|
||||||
|
[JsonSerializable(typeof(List<Endpoints4Sbox>))]
|
||||||
|
[JsonSerializable(typeof(Outbound4Sbox))]
|
||||||
|
[JsonSerializable(typeof(List<Outbound4Sbox>))]
|
||||||
|
[JsonSerializable(typeof(Rule4Sbox))]
|
||||||
|
[JsonSerializable(typeof(Ruleset4Sbox))]
|
||||||
|
[JsonSerializable(typeof(List<Rule4Sbox>))]
|
||||||
|
[JsonSerializable(typeof(List<Ruleset4Sbox>))]
|
||||||
|
[JsonSerializable(typeof(V2rayConfig))]
|
||||||
|
[JsonSerializable(typeof(Dns4Ray))]
|
||||||
|
[JsonSerializable(typeof(DnsServer4Ray))]
|
||||||
|
[JsonSerializable(typeof(Inbounds4Ray))]
|
||||||
|
[JsonSerializable(typeof(List<Inbounds4Ray>))]
|
||||||
|
[JsonSerializable(typeof(Outbounds4Ray))]
|
||||||
|
[JsonSerializable(typeof(List<Outbounds4Ray>))]
|
||||||
|
[JsonSerializable(typeof(RulesItem4Ray))]
|
||||||
|
[JsonSerializable(typeof(List<RulesItem4Ray>))]
|
||||||
|
[JsonSerializable(typeof(Finalmask4Ray))]
|
||||||
|
[JsonSerializable(typeof(string))]
|
||||||
|
[JsonSerializable(typeof(int))]
|
||||||
|
[JsonSerializable(typeof(long))]
|
||||||
|
[JsonSerializable(typeof(double))]
|
||||||
|
[JsonSerializable(typeof(decimal))]
|
||||||
|
[JsonSerializable(typeof(bool))]
|
||||||
|
[JsonSerializable(typeof(Guid))]
|
||||||
|
[JsonSerializable(typeof(DateTime))]
|
||||||
|
[JsonSerializable(typeof(DateTimeOffset))]
|
||||||
|
[JsonSerializable(typeof(TimeSpan))]
|
||||||
|
[JsonSerializable(typeof(int?))]
|
||||||
|
[JsonSerializable(typeof(long?))]
|
||||||
|
[JsonSerializable(typeof(double?))]
|
||||||
|
[JsonSerializable(typeof(bool?))]
|
||||||
|
[JsonSerializable(typeof(DateTime?))]
|
||||||
|
[JsonSerializable(typeof(Guid?))]
|
||||||
|
[JsonSerializable(typeof(string[]))]
|
||||||
|
[JsonSerializable(typeof(int[]))]
|
||||||
|
[JsonSerializable(typeof(byte[]))]
|
||||||
|
[JsonSerializable(typeof(List<string>))]
|
||||||
|
[JsonSerializable(typeof(List<int>))]
|
||||||
|
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||||
|
[JsonSerializable(typeof(Dictionary<string, object>))]
|
||||||
|
[JsonSerializable(typeof(object))]
|
||||||
|
[JsonSerializable(typeof(JsonElement))]
|
||||||
|
[JsonSerializable(typeof(JsonDocument))]
|
||||||
|
[JsonSerializable(typeof(JsonNode))]
|
||||||
|
[JsonSerializable(typeof(JsonObject))]
|
||||||
|
[JsonSerializable(typeof(JsonArray))]
|
||||||
|
internal partial class AppJsonContext : JsonSerializerContext;
|
||||||
|
|||||||
@@ -348,10 +348,9 @@ public class Utils
|
|||||||
.ToList());
|
.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<string> GetEnumNames<TEnum>() where TEnum : Enum
|
public static List<string> GetEnumNames<TEnum>() where TEnum : struct, Enum
|
||||||
{
|
{
|
||||||
return Enum.GetValues(typeof(TEnum))
|
return Enum.GetValues<TEnum>()
|
||||||
.Cast<TEnum>()
|
|
||||||
.Select(e => e.ToString())
|
.Select(e => e.ToString())
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using YamlDotNet.Core;
|
using YamlDotNet.Core;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.RepresentationModel;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
|
||||||
|
|
||||||
namespace ServiceLib.Common;
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
@@ -13,45 +12,57 @@ public class YamlUtils
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deserialize
|
/// Deserialize
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="str"></param>
|
/// <param name="str"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static T FromYaml<T>(string str)
|
public static YamlMappingNode FromYaml(string str)
|
||||||
{
|
{
|
||||||
var deserializer = new DeserializerBuilder()
|
//var deserializer = new DeserializerBuilder()
|
||||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
// .WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||||
.Build();
|
// .Build();
|
||||||
|
//try
|
||||||
|
//{
|
||||||
|
// var obj = deserializer.Deserialize<T>(str);
|
||||||
|
// return obj;
|
||||||
|
//}
|
||||||
|
//catch (Exception ex)
|
||||||
|
//{
|
||||||
|
// Logging.SaveLog(_tag, ex);
|
||||||
|
// return deserializer.Deserialize<T>("");
|
||||||
|
//}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var obj = deserializer.Deserialize<T>(str);
|
var yaml = new YamlStream();
|
||||||
return obj;
|
using var reader = new StringReader(str);
|
||||||
|
yaml.Load(reader);
|
||||||
|
var rootNode = (YamlMappingNode)yaml.Documents[0].RootNode;
|
||||||
|
return rootNode;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(_tag, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return deserializer.Deserialize<T>("");
|
return new YamlMappingNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serialize
|
/// Serialize
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj"></param>
|
/// <param name="node"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string ToYaml(object? obj)
|
public static string ToYaml(YamlMappingNode? node)
|
||||||
{
|
{
|
||||||
var result = string.Empty;
|
var result = string.Empty;
|
||||||
if (obj == null)
|
if (node == null)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
var serializer = new SerializerBuilder()
|
|
||||||
.WithNamingConvention(HyphenatedNamingConvention.Instance)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = serializer.Serialize(obj);
|
var doc = new YamlDocument(node);
|
||||||
|
var stream = new YamlStream(doc);
|
||||||
|
using var writer = new StringWriter();
|
||||||
|
stream.Save(writer, assignAnchors: false);
|
||||||
|
result = writer.ToString();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -64,9 +75,15 @@ public class YamlUtils
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mergingParser = new MergingParser(new Parser(new StringReader(str)));
|
using var reader = new StringReader(str);
|
||||||
var obj = new DeserializerBuilder().Build().Deserialize(mergingParser);
|
var parser = new Parser(reader);
|
||||||
return ToYaml(obj);
|
var mergingParser = new MergingParser(parser);
|
||||||
|
var yamlStream = new YamlStream();
|
||||||
|
yamlStream.Load(mergingParser);
|
||||||
|
using var writer = new StringWriter();
|
||||||
|
yamlStream.Save(writer, assignAnchors: false);
|
||||||
|
|
||||||
|
return writer.ToString();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public class Global
|
|||||||
public const string SingboxFakeIPFilterFileName = NamespaceSample + "singbox_fakeip_filter";
|
public const string SingboxFakeIPFilterFileName = NamespaceSample + "singbox_fakeip_filter";
|
||||||
public const string ChromeRootCertFileName = NamespaceSample + "chrome_roots_pem";
|
public const string ChromeRootCertFileName = NamespaceSample + "chrome_roots_pem";
|
||||||
public const string MozillaRootCertFileName = NamespaceSample + "mozilla_roots_pem";
|
public const string MozillaRootCertFileName = NamespaceSample + "mozilla_roots_pem";
|
||||||
|
public const string TaskXmlTemplateFileName = NamespaceSample + "TaskXmlTemplate";
|
||||||
|
|
||||||
public const string ChromeRootProvider = "chrome";
|
public const string ChromeRootProvider = "chrome";
|
||||||
public const string MozillaRootProvider = "mozilla";
|
public const string MozillaRootProvider = "mozilla";
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ public static class AutoStartupHandler
|
|||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
public static void AutoStartTaskService(string taskName, string fileName, string description)
|
public static void AutoStartTaskService(string taskName, string fileName, string description)
|
||||||
{
|
{
|
||||||
|
#if false
|
||||||
if (taskName.IsNullOrEmpty())
|
if (taskName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -117,6 +118,78 @@ public static class AutoStartupHandler
|
|||||||
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
|
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
|
||||||
|
|
||||||
taskService.RootFolder.RegisterTaskDefinition(taskName, task);
|
taskService.RootFolder.RegisterTaskDefinition(taskName, task);
|
||||||
|
#endif
|
||||||
|
if (string.IsNullOrEmpty(taskName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunSchtasks($"/Delete /TN \"{taskName}\" /F");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(fileName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var workingDir = Path.GetDirectoryName(fileName) ?? string.Empty;
|
||||||
|
|
||||||
|
var taskXml = EmbedUtils.GetEmbedText(Global.TaskXmlTemplateFileName);
|
||||||
|
|
||||||
|
taskXml = taskXml
|
||||||
|
.Replace("{{DESCRIPTION}}", System.Security.SecurityElement.Escape(description ?? ""))
|
||||||
|
.Replace("{{EXEC_PATH}}", System.Security.SecurityElement.Escape(fileName ?? ""))
|
||||||
|
.Replace("{{ARGUMENTS}}", string.Empty)
|
||||||
|
.Replace("{{WORKING_DIRECTORY}}", System.Security.SecurityElement.Escape(workingDir ?? ""));
|
||||||
|
|
||||||
|
var taskXmlFileName = Utils.GetTempPath($"{Utils.GetGuid(false)}.xml");
|
||||||
|
|
||||||
|
File.WriteAllText(taskXmlFileName, taskXml);
|
||||||
|
|
||||||
|
RunSchtasks(
|
||||||
|
"/Create",
|
||||||
|
"/TN", taskName,
|
||||||
|
"/XML", taskXmlFileName,
|
||||||
|
"/F"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool RunSchtasks(params string[] arguments)
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "schtasks.exe",
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var argument in arguments)
|
||||||
|
{
|
||||||
|
psi.ArgumentList.Add(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var process = Process.Start(psi);
|
||||||
|
|
||||||
|
if (process == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
var output = process.StandardOutput.ReadToEnd();
|
||||||
|
var error = process.StandardError.ReadToEnd();
|
||||||
|
if (!string.IsNullOrEmpty(output))
|
||||||
|
{
|
||||||
|
Logging.SaveLog($"RunSchtasks output: {output}");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(error))
|
||||||
|
{
|
||||||
|
Logging.SaveLog($"RunSchtasks error: {error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.ExitCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetAutoRunNameWindows()
|
private static string GetAutoRunNameWindows()
|
||||||
|
|||||||
@@ -80,12 +80,7 @@ public class BaseFmt
|
|||||||
{
|
{
|
||||||
var node = JsonUtils.ParseJson(item.Finalmask);
|
var node = JsonUtils.ParseJson(item.Finalmask);
|
||||||
var finalmask = node != null
|
var finalmask = node != null
|
||||||
? JsonUtils.Serialize(node, new JsonSerializerOptions
|
? JsonUtils.Serialize(node, indented: false, nullValue: true)
|
||||||
{
|
|
||||||
WriteIndented = false,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
})
|
|
||||||
: item.Finalmask;
|
: item.Finalmask;
|
||||||
dicQuery.Add("fm", Utils.UrlEncode(finalmask));
|
dicQuery.Add("fm", Utils.UrlEncode(finalmask));
|
||||||
}
|
}
|
||||||
@@ -154,12 +149,7 @@ public class BaseFmt
|
|||||||
{
|
{
|
||||||
var node = JsonUtils.ParseJson(transport.XhttpExtra);
|
var node = JsonUtils.ParseJson(transport.XhttpExtra);
|
||||||
var extra = node != null
|
var extra = node != null
|
||||||
? JsonUtils.Serialize(node, new JsonSerializerOptions
|
? JsonUtils.Serialize(node, indented: false, nullValue: true)
|
||||||
{
|
|
||||||
WriteIndented = false,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
})
|
|
||||||
: transport.XhttpExtra;
|
: transport.XhttpExtra;
|
||||||
dicQuery.Add("extra", UrlEncodeSafe(extra));
|
dicQuery.Add("extra", UrlEncodeSafe(extra));
|
||||||
}
|
}
|
||||||
@@ -215,12 +205,7 @@ public class BaseFmt
|
|||||||
{
|
{
|
||||||
var node = JsonUtils.ParseJson(finalmaskDecoded);
|
var node = JsonUtils.ParseJson(finalmaskDecoded);
|
||||||
item.Finalmask = node != null
|
item.Finalmask = node != null
|
||||||
? JsonUtils.Serialize(node, new JsonSerializerOptions
|
? JsonUtils.Serialize(node, indented: true, nullValue: true)
|
||||||
{
|
|
||||||
WriteIndented = true,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
})
|
|
||||||
: finalmaskDecoded;
|
: finalmaskDecoded;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -278,12 +263,7 @@ public class BaseFmt
|
|||||||
var node = JsonUtils.ParseJson(xhttpExtra);
|
var node = JsonUtils.ParseJson(xhttpExtra);
|
||||||
if (node != null)
|
if (node != null)
|
||||||
{
|
{
|
||||||
xhttpExtra = JsonUtils.Serialize(node, new JsonSerializerOptions
|
xhttpExtra = JsonUtils.Serialize(node, indented: true, nullValue: true);
|
||||||
{
|
|
||||||
WriteIndented = true,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -179,12 +179,7 @@ public class InnerFmt : BaseFmt
|
|||||||
if (jsonObj.TryGetPropertyValue("CustomOutboundObj", out var customOutboundNode)
|
if (jsonObj.TryGetPropertyValue("CustomOutboundObj", out var customOutboundNode)
|
||||||
&& customOutboundNode is JsonObject customOutboundObj)
|
&& customOutboundNode is JsonObject customOutboundObj)
|
||||||
{
|
{
|
||||||
var customOutboundContent = JsonUtils.Serialize(customOutboundObj, new JsonSerializerOptions
|
var customOutboundContent = JsonUtils.Serialize(customOutboundObj, indented: true, nullValue: true);
|
||||||
{
|
|
||||||
WriteIndented = true,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
});
|
|
||||||
customOutboundFilePath = WriteAllText(customOutboundContent);
|
customOutboundFilePath = WriteAllText(customOutboundContent);
|
||||||
jsonObj.Remove("CustomOutboundObj");
|
jsonObj.Remove("CustomOutboundObj");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,7 @@ public class WireguardFmt : BaseFmt
|
|||||||
{
|
{
|
||||||
var node = JsonUtils.ParseJson(finalmaskDecoded);
|
var node = JsonUtils.ParseJson(finalmaskDecoded);
|
||||||
item.Finalmask = node != null
|
item.Finalmask = node != null
|
||||||
? JsonUtils.Serialize(node, new JsonSerializerOptions
|
? JsonUtils.Serialize(node, indented: true, nullValue: true)
|
||||||
{
|
|
||||||
WriteIndented = true,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
})
|
|
||||||
: finalmaskDecoded;
|
: finalmaskDecoded;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -98,12 +93,7 @@ public class WireguardFmt : BaseFmt
|
|||||||
{
|
{
|
||||||
var node = JsonUtils.ParseJson(item.Finalmask);
|
var node = JsonUtils.ParseJson(item.Finalmask);
|
||||||
var finalmask = node != null
|
var finalmask = node != null
|
||||||
? JsonUtils.Serialize(node, new JsonSerializerOptions
|
? JsonUtils.Serialize(node, indented: false, nullValue: true)
|
||||||
{
|
|
||||||
WriteIndented = false,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
})
|
|
||||||
: item.Finalmask;
|
: item.Finalmask;
|
||||||
dicQuery.Add("fm", Utils.UrlEncode(finalmask));
|
dicQuery.Add("fm", Utils.UrlEncode(finalmask));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public static class ProxySettingWindows
|
|||||||
list.dwOptionCount = options.Length;
|
list.dwOptionCount = options.Length;
|
||||||
list.dwOptionError = 0;
|
list.dwOptionError = 0;
|
||||||
|
|
||||||
var optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
var optSize = Marshal.SizeOf<InternetConnectionOption>();
|
||||||
// make a pointer out of all that ...
|
// make a pointer out of all that ...
|
||||||
var optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
var optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
||||||
// copy the array over into that spot in memory ...
|
// copy the array over into that spot in memory ...
|
||||||
@@ -207,17 +207,17 @@ public static class ProxySettingWindows
|
|||||||
var entries = 0;
|
var entries = 0;
|
||||||
// attempt to query with 1 entry buffer
|
// attempt to query with 1 entry buffer
|
||||||
var rasEntryNames = new RASENTRYNAME[1];
|
var rasEntryNames = new RASENTRYNAME[1];
|
||||||
var bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
var bufferSize = Marshal.SizeOf<RASENTRYNAME>();
|
||||||
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
rasEntryNames[0].dwSize = Marshal.SizeOf<RASENTRYNAME>();
|
||||||
|
|
||||||
var result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
var result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
||||||
// increase buffer if the buffer is not large enough
|
// increase buffer if the buffer is not large enough
|
||||||
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
|
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
|
||||||
{
|
{
|
||||||
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
|
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf<RASENTRYNAME>()];
|
||||||
for (var i = 0; i < rasEntryNames.Length; i++)
|
for (var i = 0; i < rasEntryNames.Length; i++)
|
||||||
{
|
{
|
||||||
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
rasEntryNames[i].dwSize = Marshal.SizeOf<RASENTRYNAME>();
|
||||||
}
|
}
|
||||||
|
|
||||||
result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
||||||
@@ -258,7 +258,7 @@ public static class ProxySettingWindows
|
|||||||
|
|
||||||
static InternetConnectionOption()
|
static InternetConnectionOption()
|
||||||
{
|
{
|
||||||
Size = Marshal.SizeOf(typeof(InternetConnectionOption));
|
Size = Marshal.SizeOf<InternetConnectionOption>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nested Types
|
// Nested Types
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Configs;
|
namespace ServiceLib.Models.Configs;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
#region property
|
#region property
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Configs;
|
namespace ServiceLib.Models.Configs;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class CoreBasicItem
|
public class CoreBasicItem
|
||||||
{
|
{
|
||||||
public bool LogEnabled { get; set; }
|
public bool LogEnabled { get; set; }
|
||||||
@@ -22,7 +21,6 @@ public class CoreBasicItem
|
|||||||
public bool EnableCacheFile4Sbox { get; set; } = true;
|
public bool EnableCacheFile4Sbox { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class InItem
|
public class InItem
|
||||||
{
|
{
|
||||||
public int LocalPort { get; set; }
|
public int LocalPort { get; set; }
|
||||||
@@ -38,7 +36,6 @@ public class InItem
|
|||||||
public bool SecondLocalPortEnabled { get; set; }
|
public bool SecondLocalPortEnabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class KcpItem
|
public class KcpItem
|
||||||
{
|
{
|
||||||
public int Mtu { get; set; }
|
public int Mtu { get; set; }
|
||||||
@@ -54,7 +51,6 @@ public class KcpItem
|
|||||||
public int MaxSendingWindow { get; set; }
|
public int MaxSendingWindow { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class GrpcItem
|
public class GrpcItem
|
||||||
{
|
{
|
||||||
public int? IdleTimeout { get; set; }
|
public int? IdleTimeout { get; set; }
|
||||||
@@ -63,7 +59,6 @@ public class GrpcItem
|
|||||||
public int? InitialWindowsSize { get; set; }
|
public int? InitialWindowsSize { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class GUIItem
|
public class GUIItem
|
||||||
{
|
{
|
||||||
public bool AutoRun { get; set; }
|
public bool AutoRun { get; set; }
|
||||||
@@ -77,14 +72,12 @@ public class GUIItem
|
|||||||
public string? RootCertProvider { get; set; }
|
public string? RootCertProvider { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class MsgUIItem
|
public class MsgUIItem
|
||||||
{
|
{
|
||||||
public string? MainMsgFilter { get; set; }
|
public string? MainMsgFilter { get; set; }
|
||||||
public bool? AutoRefresh { get; set; }
|
public bool? AutoRefresh { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class UIItem
|
public class UIItem
|
||||||
{
|
{
|
||||||
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
public bool EnableAutoAdjustMainLvColWidth { get; set; }
|
||||||
@@ -106,7 +99,6 @@ public class UIItem
|
|||||||
public bool HideColumnIpInfo { get; set; }
|
public bool HideColumnIpInfo { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ConstItem
|
public class ConstItem
|
||||||
{
|
{
|
||||||
public string? SubConvertUrl { get; set; }
|
public string? SubConvertUrl { get; set; }
|
||||||
@@ -115,7 +107,6 @@ public class ConstItem
|
|||||||
public string? RouteRulesTemplateSourceUrl { get; set; }
|
public string? RouteRulesTemplateSourceUrl { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class KeyEventItem
|
public class KeyEventItem
|
||||||
{
|
{
|
||||||
public EGlobalHotkey EGlobalHotkey { get; set; }
|
public EGlobalHotkey EGlobalHotkey { get; set; }
|
||||||
@@ -129,7 +120,6 @@ public class KeyEventItem
|
|||||||
public int? KeyCode { get; set; }
|
public int? KeyCode { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class CoreTypeItem
|
public class CoreTypeItem
|
||||||
{
|
{
|
||||||
public EConfigType ConfigType { get; set; }
|
public EConfigType ConfigType { get; set; }
|
||||||
@@ -137,7 +127,6 @@ public class CoreTypeItem
|
|||||||
public ECoreType CoreType { get; set; }
|
public ECoreType CoreType { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class TunModeItem
|
public class TunModeItem
|
||||||
{
|
{
|
||||||
public bool EnableTun { get; set; }
|
public bool EnableTun { get; set; }
|
||||||
@@ -153,7 +142,6 @@ public class TunModeItem
|
|||||||
public string IPv6Address { get; set; }
|
public string IPv6Address { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class SpeedTestItem
|
public class SpeedTestItem
|
||||||
{
|
{
|
||||||
public int SpeedTestTimeout { get; set; }
|
public int SpeedTestTimeout { get; set; }
|
||||||
@@ -166,7 +154,6 @@ public class SpeedTestItem
|
|||||||
public int? SpeedTestDelayInterval { get; set; }
|
public int? SpeedTestDelayInterval { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RoutingBasicItem
|
public class RoutingBasicItem
|
||||||
{
|
{
|
||||||
public string DomainStrategy { get; set; }
|
public string DomainStrategy { get; set; }
|
||||||
@@ -174,7 +161,6 @@ public class RoutingBasicItem
|
|||||||
public string RoutingIndexId { get; set; }
|
public string RoutingIndexId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ColumnItem
|
public class ColumnItem
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
@@ -182,7 +168,6 @@ public class ColumnItem
|
|||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class Mux4RayItem
|
public class Mux4RayItem
|
||||||
{
|
{
|
||||||
public int? Concurrency { get; set; }
|
public int? Concurrency { get; set; }
|
||||||
@@ -190,7 +175,6 @@ public class Mux4RayItem
|
|||||||
public string? XudpProxyUDP443 { get; set; }
|
public string? XudpProxyUDP443 { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class Mux4SboxItem
|
public class Mux4SboxItem
|
||||||
{
|
{
|
||||||
public string Protocol { get; set; }
|
public string Protocol { get; set; }
|
||||||
@@ -198,7 +182,6 @@ public class Mux4SboxItem
|
|||||||
public bool? Padding { get; set; }
|
public bool? Padding { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class HysteriaItem
|
public class HysteriaItem
|
||||||
{
|
{
|
||||||
public int UpMbps { get; set; }
|
public int UpMbps { get; set; }
|
||||||
@@ -206,7 +189,6 @@ public class HysteriaItem
|
|||||||
public int HopInterval { get; set; } = Global.Hysteria2DefaultHopInt;
|
public int HopInterval { get; set; } = Global.Hysteria2DefaultHopInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ClashUIItem
|
public class ClashUIItem
|
||||||
{
|
{
|
||||||
public bool EnableIPv6 { get; set; }
|
public bool EnableIPv6 { get; set; }
|
||||||
@@ -219,7 +201,6 @@ public class ClashUIItem
|
|||||||
public List<ColumnItem> ConnectionsColumnItem { get; set; }
|
public List<ColumnItem> ConnectionsColumnItem { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class SystemProxyItem
|
public class SystemProxyItem
|
||||||
{
|
{
|
||||||
public ESysProxyType SysProxyType { get; set; }
|
public ESysProxyType SysProxyType { get; set; }
|
||||||
@@ -230,7 +211,6 @@ public class SystemProxyItem
|
|||||||
public string? CustomSystemProxyScriptPath { get; set; }
|
public string? CustomSystemProxyScriptPath { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class WebDavItem
|
public class WebDavItem
|
||||||
{
|
{
|
||||||
public string? Url { get; set; }
|
public string? Url { get; set; }
|
||||||
@@ -239,7 +219,6 @@ public class WebDavItem
|
|||||||
public string? DirName { get; set; }
|
public string? DirName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class CheckUpdateItem
|
public class CheckUpdateItem
|
||||||
{
|
{
|
||||||
public bool UpdateViaProxy { get; set; } = true;
|
public bool UpdateViaProxy { get; set; } = true;
|
||||||
@@ -247,7 +226,6 @@ public class CheckUpdateItem
|
|||||||
public List<string>? CheckPreReleaseCoreTypes { get; set; }
|
public List<string>? CheckPreReleaseCoreTypes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class Fragment4RayItem
|
public class Fragment4RayItem
|
||||||
{
|
{
|
||||||
public string? Packets { get; set; }
|
public string? Packets { get; set; }
|
||||||
@@ -262,7 +240,6 @@ public class Fragment4RayItem
|
|||||||
// migration end
|
// migration end
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class WindowSizeItem
|
public class WindowSizeItem
|
||||||
{
|
{
|
||||||
public string TypeName { get; set; }
|
public string TypeName { get; set; }
|
||||||
@@ -270,7 +247,6 @@ public class WindowSizeItem
|
|||||||
public int Height { get; set; }
|
public int Height { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class SimpleDNSItem
|
public class SimpleDNSItem
|
||||||
{
|
{
|
||||||
public bool? UseSystemHosts { get; set; }
|
public bool? UseSystemHosts { get; set; }
|
||||||
@@ -293,7 +269,6 @@ public class SimpleDNSItem
|
|||||||
public bool? EnableHappyEyeballs { get; set; }
|
public bool? EnableHappyEyeballs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class HappyEyeballs4RayItem
|
public class HappyEyeballs4RayItem
|
||||||
{
|
{
|
||||||
public int? TryDelayMs { get; set; }
|
public int? TryDelayMs { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.CoreConfigs;
|
namespace ServiceLib.Models.CoreConfigs;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class CoreInfo
|
public class CoreInfo
|
||||||
{
|
{
|
||||||
public ECoreType CoreType { get; set; }
|
public ECoreType CoreType { get; set; }
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ public class Route4Sbox
|
|||||||
public string? final { get; set; }
|
public string? final { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class Rule4Sbox
|
public class Rule4Sbox
|
||||||
{
|
{
|
||||||
public string? outbound { get; set; }
|
public string? outbound { get; set; }
|
||||||
@@ -103,7 +102,6 @@ public class Rule4Sbox
|
|||||||
public bool? speculative { get; set; }
|
public bool? speculative { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class Inbound4Sbox
|
public class Inbound4Sbox
|
||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
@@ -232,7 +230,7 @@ public class Reality4Sbox
|
|||||||
public class Transport4Sbox
|
public class Transport4Sbox
|
||||||
{
|
{
|
||||||
public string? type { get; set; }
|
public string? type { get; set; }
|
||||||
public object? host { get; set; }
|
public JsonNode? host { get; set; }
|
||||||
public string? path { get; set; }
|
public string? path { get; set; }
|
||||||
public Headers4Sbox? headers { get; set; }
|
public Headers4Sbox? headers { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace ServiceLib.Models.CoreConfigs;
|
|||||||
public class V2rayConfig
|
public class V2rayConfig
|
||||||
{
|
{
|
||||||
public Log4Ray log { get; set; }
|
public Log4Ray log { get; set; }
|
||||||
public object dns { get; set; }
|
public JsonObject? dns { get; set; }
|
||||||
public FakeDns4Ray? fakedns { get; set; }
|
public FakeDns4Ray? fakedns { get; set; }
|
||||||
public List<Inbounds4Ray> inbounds { get; set; }
|
public List<Inbounds4Ray> inbounds { get; set; }
|
||||||
public List<Outbounds4Ray> outbounds { get; set; }
|
public List<Outbounds4Ray> outbounds { get; set; }
|
||||||
@@ -130,7 +130,7 @@ public class Outboundsettings4Ray
|
|||||||
|
|
||||||
public string? secretKey { get; set; }
|
public string? secretKey { get; set; }
|
||||||
|
|
||||||
public object? address { get; set; }
|
public JsonNode? address { get; set; }
|
||||||
|
|
||||||
public int? port { get; set; }
|
public int? port { get; set; }
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ public class Outboundsettings4Ray
|
|||||||
|
|
||||||
public string? email { get; set; }
|
public string? email { get; set; }
|
||||||
|
|
||||||
public object? headers { get; set; }
|
public JsonNode? headers { get; set; }
|
||||||
|
|
||||||
public List<WireguardPeer4Ray>? peers { get; set; }
|
public List<WireguardPeer4Ray>? peers { get; set; }
|
||||||
|
|
||||||
@@ -199,8 +199,8 @@ public class Response4Ray
|
|||||||
|
|
||||||
public class Dns4Ray
|
public class Dns4Ray
|
||||||
{
|
{
|
||||||
public Dictionary<string, object>? hosts { get; set; }
|
public Dictionary<string, JsonNode>? hosts { get; set; }
|
||||||
public List<object> servers { get; set; }
|
public List<JsonNode> servers { get; set; }
|
||||||
public bool? serveStale { get; set; }
|
public bool? serveStale { get; set; }
|
||||||
public bool? enableParallelQuery { get; set; }
|
public bool? enableParallelQuery { get; set; }
|
||||||
public string? queryStrategy { get; set; }
|
public string? queryStrategy { get; set; }
|
||||||
@@ -226,7 +226,6 @@ public class Routing4Ray
|
|||||||
public List<BalancersItem4Ray>? balancers { get; set; }
|
public List<BalancersItem4Ray>? balancers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RulesItem4Ray
|
public class RulesItem4Ray
|
||||||
{
|
{
|
||||||
public string? type { get; set; }
|
public string? type { get; set; }
|
||||||
@@ -321,7 +320,7 @@ public class StreamSettings4Ray
|
|||||||
public HysteriaSettings4Ray? hysteriaSettings { get; set; }
|
public HysteriaSettings4Ray? hysteriaSettings { get; set; }
|
||||||
public MasqueSettings4Ray? masqueSettings { get; set; }
|
public MasqueSettings4Ray? masqueSettings { get; set; }
|
||||||
|
|
||||||
public object? finalmask { get; set; }
|
public JsonObject? finalmask { get; set; }
|
||||||
|
|
||||||
public Sockopt4Ray? sockopt { get; set; }
|
public Sockopt4Ray? sockopt { get; set; }
|
||||||
}
|
}
|
||||||
@@ -363,9 +362,9 @@ public class Header4Ray
|
|||||||
{
|
{
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
|
|
||||||
public object request { get; set; }
|
public JsonObject request { get; set; }
|
||||||
|
|
||||||
public object response { get; set; }
|
public JsonObject response { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KcpSettings4Ray
|
public class KcpSettings4Ray
|
||||||
@@ -411,7 +410,7 @@ public class XhttpSettings4Ray
|
|||||||
public string? path { get; set; }
|
public string? path { get; set; }
|
||||||
public string? host { get; set; }
|
public string? host { get; set; }
|
||||||
public string? mode { get; set; }
|
public string? mode { get; set; }
|
||||||
public object? extra { get; set; }
|
public JsonObject? extra { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HttpSettings4Ray
|
public class HttpSettings4Ray
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public partial class ClashProxyModel : ReactiveObject
|
public partial class ClashProxyModel : ReactiveObject
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public partial class ProfileItemModel : ReactiveObject
|
public partial class ProfileItemModel : ReactiveObject
|
||||||
{
|
{
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RoutingItemModel : RoutingItem
|
public class RoutingItemModel : RoutingItem
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RoutingTemplate
|
public class RoutingTemplate
|
||||||
{
|
{
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RulesItemModel : RulesItem
|
public class RulesItemModel : RulesItem
|
||||||
{
|
{
|
||||||
public string InboundTags { get; set; }
|
public string InboundTags { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ServerSpeedItem : ServerStatItem
|
public class ServerSpeedItem : ServerStatItem
|
||||||
{
|
{
|
||||||
public long ProxyUp { get; set; }
|
public long ProxyUp { get; set; }
|
||||||
@@ -12,7 +11,6 @@ public class ServerSpeedItem : ServerStatItem
|
|||||||
public long DirectDown { get; set; }
|
public long DirectDown { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class TrafficItem
|
public class TrafficItem
|
||||||
{
|
{
|
||||||
public ulong Up { get; set; }
|
public ulong Up { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ServerTestItem
|
public class ServerTestItem
|
||||||
{
|
{
|
||||||
public string? IndexId { get; set; }
|
public string? IndexId { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Dto;
|
namespace ServiceLib.Models.Dto;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class SpeedTestResult
|
public class SpeedTestResult
|
||||||
{
|
{
|
||||||
public string? IndexId { get; set; }
|
public string? IndexId { get; set; }
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ public class SsSIP008
|
|||||||
public List<SsServer>? servers { get; set; }
|
public List<SsServer>? servers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class SsServer
|
public class SsServer
|
||||||
{
|
{
|
||||||
public string? remarks { get; set; }
|
public string? remarks { get; set; }
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ namespace ServiceLib.Models.Dto;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// https://github.com/2dust/v2rayN/wiki/
|
/// https://github.com/2dust/v2rayN/wiki/
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
|
||||||
public class VmessQRCode
|
public class VmessQRCode
|
||||||
{
|
{
|
||||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class DNSItem
|
public class DNSItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class FullConfigTemplateItem
|
public class FullConfigTemplateItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ProfileExItem
|
public class ProfileExItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Obsolete("Use ProtocolExtraItem instead.")]
|
[Obsolete("Use ProtocolExtraItem instead.")]
|
||||||
[Serializable]
|
|
||||||
public class ProfileGroupItem
|
public class ProfileGroupItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ProfileItem
|
public class ProfileItem
|
||||||
{
|
{
|
||||||
private ProtocolExtraItem? _protocolExtraCache;
|
private ProtocolExtraItem? _protocolExtraCache;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RoutingItem
|
public class RoutingItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class RulesItem
|
public class RulesItem
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class ServerStatItem
|
public class ServerStatItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
namespace ServiceLib.Models.Entities;
|
namespace ServiceLib.Models.Entities;
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class SubItem
|
public class SubItem
|
||||||
{
|
{
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-16"?>
|
||||||
|
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
||||||
|
<RegistrationInfo>
|
||||||
|
<Description>{{DESCRIPTION}}</Description>
|
||||||
|
</RegistrationInfo>
|
||||||
|
<Triggers>
|
||||||
|
<LogonTrigger>
|
||||||
|
<Enabled>true</Enabled>
|
||||||
|
</LogonTrigger>
|
||||||
|
</Triggers>
|
||||||
|
<Principals>
|
||||||
|
<Principal id="Author">
|
||||||
|
<LogonType>InteractiveToken</LogonType>
|
||||||
|
<RunLevel>HighestAvailable</RunLevel>
|
||||||
|
</Principal>
|
||||||
|
</Principals>
|
||||||
|
<Actions Context="Author">
|
||||||
|
<Exec>
|
||||||
|
<Command>{{EXEC_PATH}}</Command>
|
||||||
|
<Arguments>{{ARGUMENTS}}</Arguments>
|
||||||
|
<WorkingDirectory>{{WORKING_DIRECTORY}}</WorkingDirectory>
|
||||||
|
</Exec>
|
||||||
|
</Actions>
|
||||||
|
</Task>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
<PackageReference Include="QRCoder" />
|
<PackageReference Include="QRCoder" />
|
||||||
<PackageReference Include="CliWrap" />
|
<PackageReference Include="CliWrap" />
|
||||||
<PackageReference Include="ZXing.Net.Bindings.SkiaSharp" />
|
<PackageReference Include="ZXing.Net.Bindings.SkiaSharp" />
|
||||||
<PackageReference Include="TaskScheduler" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -45,6 +44,7 @@
|
|||||||
<EmbeddedResource Include="Sample\SampleTunRules" />
|
<EmbeddedResource Include="Sample\SampleTunRules" />
|
||||||
<EmbeddedResource Include="Sample\SingboxSampleClientConfig" />
|
<EmbeddedResource Include="Sample\SingboxSampleClientConfig" />
|
||||||
<EmbeddedResource Include="Sample\SingboxSampleOutbound" />
|
<EmbeddedResource Include="Sample\SingboxSampleOutbound" />
|
||||||
|
<EmbeddedResource Include="Sample\TaskXmlTemplate" />
|
||||||
<EmbeddedResource Include="Sample\tun_singbox_dns" />
|
<EmbeddedResource Include="Sample\tun_singbox_dns" />
|
||||||
<EmbeddedResource Include="Sample\tun_singbox_inbound" />
|
<EmbeddedResource Include="Sample\tun_singbox_inbound" />
|
||||||
<EmbeddedResource Include="Sample\tun_singbox_rules" />
|
<EmbeddedResource Include="Sample\tun_singbox_rules" />
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ public class CoreConfigClashService(Config config, bool isTunEnabled)
|
|||||||
//YAML anchors
|
//YAML anchors
|
||||||
if (txtFile.Contains("<<:") && txtFile.Contains('*') && txtFile.Contains('&'))
|
if (txtFile.Contains("<<:") && txtFile.Contains('*') && txtFile.Contains('&'))
|
||||||
{
|
{
|
||||||
txtFile = YamlUtils.PreprocessYaml(txtFile);
|
txtFile = YamlUtils.PreprocessYaml(txtFile) ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
var fileContent = YamlUtils.FromYaml(txtFile);
|
||||||
if (fileContent == null)
|
if (fileContent == null)
|
||||||
{
|
{
|
||||||
ret.Msg = ResUI.FailedConversionConfiguration;
|
ret.Msg = ResUI.FailedConversionConfiguration;
|
||||||
@@ -72,29 +72,38 @@ public class CoreConfigClashService(Config config, bool isTunEnabled)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//mixed-port
|
//mixed-port
|
||||||
fileContent["mixed-port"] = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
//fileContent["mixed-port"] = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
|
fileContent.Children[new YamlScalarNode("mixed-port")] = new YamlScalarNode(AppManager.Instance.GetLocalPort(EInboundProtocol.socks).ToString());
|
||||||
//log-level
|
//log-level
|
||||||
fileContent["log-level"] = GetLogLevel(config.CoreBasicItem.Loglevel);
|
//fileContent["log-level"] = GetLogLevel(config.CoreBasicItem.Loglevel);
|
||||||
|
fileContent.Children[new YamlScalarNode("log-level")] = new YamlScalarNode(GetLogLevel(config.CoreBasicItem.Loglevel));
|
||||||
|
|
||||||
//external-controller
|
//external-controller
|
||||||
fileContent["external-controller"] = $"{Global.Loopback}:{AppManager.Instance.StatePort2}";
|
//fileContent["external-controller"] = $"{Global.Loopback}:{AppManager.Instance.StatePort2}";
|
||||||
fileContent.Remove("secret");
|
fileContent.Children[new YamlScalarNode("external-controller")] = new YamlScalarNode($"{Global.Loopback}:{AppManager.Instance.StatePort2}");
|
||||||
|
//fileContent.Remove("secret");
|
||||||
|
fileContent.Children.Remove(new YamlScalarNode("secret"));
|
||||||
//allow-lan
|
//allow-lan
|
||||||
if (config.Inbound.First().AllowLANConn)
|
if (config.Inbound.First().AllowLANConn)
|
||||||
{
|
{
|
||||||
fileContent["allow-lan"] = "true";
|
//fileContent["allow-lan"] = "true";
|
||||||
fileContent["bind-address"] = "*";
|
fileContent.Children[new YamlScalarNode("allow-lan")] = new YamlScalarNode("true");
|
||||||
|
//fileContent["bind-address"] = "*";
|
||||||
|
fileContent.Children[new YamlScalarNode("bind-address")] = new YamlScalarNode("*");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fileContent["allow-lan"] = "false";
|
//fileContent["allow-lan"] = "false";
|
||||||
|
fileContent.Children[new YamlScalarNode("allow-lan")] = new YamlScalarNode("false");
|
||||||
}
|
}
|
||||||
|
|
||||||
//ipv6
|
//ipv6
|
||||||
fileContent["ipv6"] = config.ClashUIItem.EnableIPv6;
|
//fileContent["ipv6"] = config.ClashUIItem.EnableIPv6;
|
||||||
|
fileContent.Children[new YamlScalarNode("ipv6")] = new YamlScalarNode(config.ClashUIItem.EnableIPv6.ToString().ToLowerInvariant());
|
||||||
|
|
||||||
//mode
|
//mode
|
||||||
fileContent.TryAdd("mode", nameof(ERuleMode.Rule));
|
//fileContent.TryAdd("mode", nameof(ERuleMode.Rule));
|
||||||
|
fileContent.Children.TryAdd(new YamlScalarNode("mode"), new YamlScalarNode(nameof(ERuleMode.Rule)));
|
||||||
|
|
||||||
//enable tun mode
|
//enable tun mode
|
||||||
if (isTunEnabled)
|
if (isTunEnabled)
|
||||||
@@ -102,10 +111,11 @@ public class CoreConfigClashService(Config config, bool isTunEnabled)
|
|||||||
var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
||||||
if (tun.IsNotEmpty())
|
if (tun.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
var tunContent = YamlUtils.FromYaml(tun);
|
||||||
if (tunContent != null)
|
if (tunContent != null)
|
||||||
{
|
{
|
||||||
fileContent["tun"] = tunContent["tun"];
|
//fileContent["tun"] = tunContent["tun"];
|
||||||
|
fileContent.Children[new YamlScalarNode("tun")] = tunContent.Children[new YamlScalarNode("tun")];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,27 +130,27 @@ public class CoreConfigClashService(Config config, bool isTunEnabled)
|
|||||||
Logging.SaveLog($"{_tag}-Mixin", ex);
|
Logging.SaveLog($"{_tag}-Mixin", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mihomo parses plain values such as 815458e4 as floats, so quote REALITY short IDs.
|
//// Mihomo parses plain values such as 815458e4 as floats, so quote REALITY short IDs.
|
||||||
var originalRealityShortIds = new List<(Dictionary<object, object> RealityOptions, string ShortId)>();
|
//var originalRealityShortIds = new List<(Dictionary<object, object> RealityOptions, string ShortId)>();
|
||||||
if (fileContent.GetValueOrDefault("proxies") is List<object> proxies)
|
//if (fileContent.GetValueOrDefault("proxies") is List<object> proxies)
|
||||||
{
|
//{
|
||||||
foreach (var proxy in proxies.OfType<Dictionary<object, object>>())
|
// foreach (var proxy in proxies.OfType<Dictionary<object, object>>())
|
||||||
{
|
// {
|
||||||
if (proxy.GetValueOrDefault("reality-opts") is Dictionary<object, object> realityOptions
|
// if (proxy.GetValueOrDefault("reality-opts") is Dictionary<object, object> realityOptions
|
||||||
&& realityOptions.GetValueOrDefault("short-id") is string shortId
|
// && realityOptions.GetValueOrDefault("short-id") is string shortId
|
||||||
&& !shortId.StartsWith(tagYamlStr2, StringComparison.Ordinal))
|
// && !shortId.StartsWith(tagYamlStr2, StringComparison.Ordinal))
|
||||||
{
|
// {
|
||||||
originalRealityShortIds.Add((realityOptions, shortId));
|
// originalRealityShortIds.Add((realityOptions, shortId));
|
||||||
realityOptions["short-id"] = new YamlScalarNode(shortId) { Style = ScalarStyle.DoubleQuoted };
|
// realityOptions["short-id"] = new YamlScalarNode(shortId) { Style = ScalarStyle.DoubleQuoted };
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3);
|
||||||
foreach (var (realityOptions, shortId) in originalRealityShortIds)
|
//foreach (var (realityOptions, shortId) in originalRealityShortIds)
|
||||||
{
|
//{
|
||||||
realityOptions["short-id"] = shortId;
|
// realityOptions["short-id"] = shortId;
|
||||||
}
|
//}
|
||||||
await File.WriteAllTextAsync(fileName, txtFileNew);
|
await File.WriteAllTextAsync(fileName, txtFileNew);
|
||||||
//check again
|
//check again
|
||||||
if (!File.Exists(fileName))
|
if (!File.Exists(fileName))
|
||||||
@@ -161,7 +171,7 @@ public class CoreConfigClashService(Config config, bool isTunEnabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task MixinContent(Dictionary<string, object> fileContent, ProfileItem node)
|
private async Task MixinContent(YamlMappingNode fileContent, ProfileItem node)
|
||||||
{
|
{
|
||||||
if (!config.ClashUIItem.EnableMixinContent)
|
if (!config.ClashUIItem.EnableMixinContent)
|
||||||
{
|
{
|
||||||
@@ -177,80 +187,116 @@ public class CoreConfigClashService(Config config, bool isTunEnabled)
|
|||||||
|
|
||||||
var txtFile = await File.ReadAllTextAsync(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
var txtFile = await File.ReadAllTextAsync(Utils.GetConfigPath(Global.ClashMixinConfigFileName));
|
||||||
|
|
||||||
var mixinContent = YamlUtils.FromYaml<Dictionary<string, object>>(txtFile);
|
var mixinContent = YamlUtils.FromYaml(txtFile);
|
||||||
if (mixinContent == null)
|
if (mixinContent == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (var item in mixinContent)
|
foreach (var (keyNode, valueNode) in mixinContent.Children)
|
||||||
{
|
{
|
||||||
if (!isTunEnabled && item.Key == "tun")
|
if (keyNode is not YamlScalarNode scalarKey)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var key = scalarKey.Value ?? "";
|
||||||
|
if (!isTunEnabled && key == "tun")
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.Key.StartsWith("prepend-")
|
if (key.StartsWith("prepend-")
|
||||||
|| item.Key.StartsWith("append-")
|
|| key.StartsWith("append-")
|
||||||
|| item.Key.StartsWith("removed-"))
|
|| key.StartsWith("removed-"))
|
||||||
{
|
{
|
||||||
ModifyContentMerge(fileContent, item.Key, item.Value);
|
ModifyContentMerge(fileContent, key, valueNode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fileContent[item.Key] = item.Value;
|
fileContent.Children[keyNode] = valueNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ModifyContentMerge(Dictionary<string, object> fileContent, string key, object value)
|
private void ModifyContentMerge(YamlMappingNode fileContent, YamlNode keyNode, YamlNode valueNode)
|
||||||
{
|
{
|
||||||
|
if (keyNode is not YamlScalarNode { Value: string key })
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var blPrepend = false;
|
var blPrepend = false;
|
||||||
var blRemoved = false;
|
var blRemoved = false;
|
||||||
|
string realKey;
|
||||||
|
|
||||||
if (key.StartsWith("prepend-"))
|
if (key.StartsWith("prepend-"))
|
||||||
{
|
{
|
||||||
blPrepend = true;
|
blPrepend = true;
|
||||||
key = key.Replace("prepend-", "");
|
realKey = key["prepend-".Length..];
|
||||||
}
|
}
|
||||||
else if (key.StartsWith("append-"))
|
else if (key.StartsWith("append-"))
|
||||||
{
|
{
|
||||||
blPrepend = false;
|
realKey = key["append-".Length..];
|
||||||
key = key.Replace("append-", "");
|
|
||||||
}
|
}
|
||||||
else if (key.StartsWith("removed-"))
|
else if (key.StartsWith("removed-"))
|
||||||
{
|
{
|
||||||
blRemoved = true;
|
blRemoved = true;
|
||||||
key = key.Replace("removed-", "");
|
realKey = key["removed-".Length..];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blRemoved && fileContent.TryAdd(key, value))
|
var targetKeyNode = new YamlScalarNode(realKey);
|
||||||
|
|
||||||
|
if (!blRemoved && fileContent.Children.TryAdd(targetKeyNode, valueNode))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fileContent.Children.TryGetValue(targetKeyNode, out var existingNode) ||
|
||||||
|
existingNode is not YamlSequenceNode lstOri ||
|
||||||
|
valueNode is not YamlSequenceNode lstValue)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var lstOri = (List<object>)fileContent[key];
|
|
||||||
var lstValue = (List<object>)value;
|
|
||||||
|
|
||||||
if (blRemoved)
|
if (blRemoved)
|
||||||
{
|
{
|
||||||
foreach (var item in lstValue)
|
var removePrefixes = lstValue.Children
|
||||||
|
.OfType<YamlScalarNode>()
|
||||||
|
.Select(s => s.Value)
|
||||||
|
.Where(v => !string.IsNullOrEmpty(v))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
for (var i = lstOri.Children.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
lstOri.RemoveAll(t => t.ToString().StartsWith(item.ToString()));
|
if (lstOri.Children[i] is YamlScalarNode { Value: not null } itemScalar)
|
||||||
|
{
|
||||||
|
if (removePrefixes.Any(prefix => itemScalar.Value.StartsWith(prefix!)))
|
||||||
|
{
|
||||||
|
lstOri.Children.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blPrepend)
|
if (blPrepend)
|
||||||
{
|
{
|
||||||
lstValue.Reverse();
|
// Insert in reverse order to maintain original sequence at index 0
|
||||||
lstValue.ForEach(item => lstOri.Insert(0, item));
|
for (var i = lstValue.Children.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
lstOri.Children.Insert(0, lstValue.Children[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lstValue.ForEach(lstOri.Add);
|
foreach (var item in lstValue.Children)
|
||||||
|
{
|
||||||
|
lstOri.Children.Add(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -525,7 +525,7 @@ public partial class CoreConfigSingboxService
|
|||||||
transport.type = nameof(ETransport.http);
|
transport.type = nameof(ETransport.http);
|
||||||
transport.host = transportExtra.Host.IsNullOrEmpty()
|
transport.host = transportExtra.Host.IsNullOrEmpty()
|
||||||
? null
|
? null
|
||||||
: Utils.String2List(transportExtra.Host);
|
: JsonUtils.SerializeToArray(Utils.String2List(transportExtra.Host));
|
||||||
transport.path = transportExtra.Path.NullIfEmpty();
|
transport.path = transportExtra.Path.NullIfEmpty();
|
||||||
if (!useragentValue.IsNullOrEmpty())
|
if (!useragentValue.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DNS routing
|
// DNS routing
|
||||||
var dnsObj = JsonUtils.SerializeToNode(_coreConfig.dns);
|
var dnsNode = JsonUtils.SerializeToNode(_coreConfig.dns);
|
||||||
if (dnsObj == null)
|
if (dnsNode is not JsonObject dnsObj)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsObj["tag"] = Global.DnsTag;
|
dnsObj["tag"] = Global.DnsTag;
|
||||||
_coreConfig.dns = JsonUtils.Deserialize<Dns4Ray>(JsonUtils.Serialize(dnsObj));
|
_coreConfig.dns = dnsObj;
|
||||||
_coreConfig.routing.rules.Add(new RulesItem4Ray
|
_coreConfig.routing.rules.Add(new RulesItem4Ray
|
||||||
{
|
{
|
||||||
type = "field",
|
type = "field",
|
||||||
@@ -34,7 +34,7 @@ public partial class CoreConfigV2rayService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var simpleDnsItem = context.SimpleDnsItem;
|
var simpleDnsItem = context.SimpleDnsItem;
|
||||||
var dnsItem = _coreConfig.dns as Dns4Ray ?? new Dns4Ray();
|
var dnsItem = new Dns4Ray();
|
||||||
|
|
||||||
var strategy4Freedom = simpleDnsItem?.Strategy4Freedom ?? Global.AsIs;
|
var strategy4Freedom = simpleDnsItem?.Strategy4Freedom ?? Global.AsIs;
|
||||||
//Outbound Freedom domainStrategy
|
//Outbound Freedom domainStrategy
|
||||||
@@ -117,7 +117,7 @@ public partial class CoreConfigV2rayService
|
|||||||
balancerTag = finalRule.balancerTag,
|
balancerTag = finalRule.balancerTag,
|
||||||
});
|
});
|
||||||
|
|
||||||
_coreConfig.dns = dnsItem;
|
_coreConfig.dns = (JsonObject)JsonUtils.SerializeToNode(dnsItem);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -317,7 +317,7 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
if (!useDirectDns)
|
if (!useDirectDns)
|
||||||
{
|
{
|
||||||
dnsItem.servers.AddRange(remoteDNSAddress);
|
dnsItem.servers.AddRange(JsonUtils.SerializeToArray(remoteDNSAddress));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -326,8 +326,7 @@ public partial class CoreConfigV2rayService
|
|||||||
var dnsServer = CreateDnsServer(dns, []);
|
var dnsServer = CreateDnsServer(dns, []);
|
||||||
dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}";
|
dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}";
|
||||||
dnsServer.skipFallback = false;
|
dnsServer.skipFallback = false;
|
||||||
dnsItem.servers.Add(JsonUtils.SerializeToNode(dnsServer,
|
dnsItem.servers.Add(JsonUtils.SerializeToNode(dnsServer));
|
||||||
new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -382,8 +381,7 @@ public partial class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}";
|
dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}";
|
||||||
}
|
}
|
||||||
var dnsServerNode = JsonUtils.SerializeToNode(dnsServer,
|
var dnsServerNode = JsonUtils.SerializeToNode(dnsServer);
|
||||||
new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
|
|
||||||
dnsItem.servers.Add(dnsServerNode);
|
dnsItem.servers.Add(dnsServerNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,12 +394,12 @@ public partial class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dnsItem.hosts ??= new Dictionary<string, object>();
|
dnsItem.hosts ??= new Dictionary<string, JsonNode>();
|
||||||
if (simpleDNSItem.AddCommonHosts == true)
|
if (simpleDNSItem.AddCommonHosts == true)
|
||||||
{
|
{
|
||||||
dnsItem.hosts = Global.PredefinedHosts.ToDictionary(
|
dnsItem.hosts = Global.PredefinedHosts.ToDictionary(
|
||||||
kvp => kvp.Key,
|
kvp => kvp.Key,
|
||||||
kvp => (object)kvp.Value
|
kvp => (JsonNode)JsonUtils.SerializeToArray(kvp.Value)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,14 +412,14 @@ public partial class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
foreach (var host in systemHosts)
|
foreach (var host in systemHosts)
|
||||||
{
|
{
|
||||||
normalHost.TryAdd(host.Key, new List<string> { host.Value });
|
normalHost.TryAdd(host.Key, JsonUtils.SerializeToArray(new List<string> { host.Value }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var kvp in Utils.ParseHostsToDictionary(simpleDNSItem.Hosts))
|
foreach (var kvp in Utils.ParseHostsToDictionary(simpleDNSItem.Hosts))
|
||||||
{
|
{
|
||||||
dnsItem.hosts[kvp.Key] = kvp.Value;
|
dnsItem.hosts[kvp.Key] = JsonUtils.SerializeToArray(kvp.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,8 +447,8 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var obj = JsonUtils.ParseJson(customDNS);
|
var node = JsonUtils.ParseJson(customDNS);
|
||||||
if (obj is null)
|
if (node is not JsonObject obj)
|
||||||
{
|
{
|
||||||
List<string> servers = [];
|
List<string> servers = [];
|
||||||
var arrDNS = customDNS.Split(',');
|
var arrDNS = customDNS.Split(',');
|
||||||
@@ -458,8 +456,7 @@ public partial class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
servers.Add(str);
|
servers.Add(str);
|
||||||
}
|
}
|
||||||
obj = JsonUtils.ParseJson("{}");
|
obj = new JsonObject { ["servers"] = JsonUtils.SerializeToNode(servers) };
|
||||||
obj["servers"] = JsonUtils.SerializeToNode(servers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append to dns settings
|
// Append to dns settings
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ public partial class CoreConfigV2rayService
|
|||||||
};
|
};
|
||||||
var setting = new Outboundsettings4Ray
|
var setting = new Outboundsettings4Ray
|
||||||
{
|
{
|
||||||
address = Utils.String2List(protocolExtra.WgInterfaceAddress)?.Select(s => s.Trim()).ToList() ?? ["172.16.0.2/32"],
|
address = JsonUtils.SerializeToArray(Utils.String2List(protocolExtra.WgInterfaceAddress)?.Select(s => s.Trim()).ToList() ?? ["172.16.0.2/32"]),
|
||||||
secretKey = _node.Password,
|
secretKey = _node.Password,
|
||||||
reserved = Utils.String2List(protocolExtra.WgReserved)?.Select(s => s.Trim()).Select(int.Parse).ToList(),
|
reserved = Utils.String2List(protocolExtra.WgReserved)?.Select(s => s.Trim()).Select(int.Parse).ToList(),
|
||||||
mtu = protocolExtra.WgMtu > 0 ? protocolExtra.WgMtu : Global.TunMtus.First(),
|
mtu = protocolExtra.WgMtu > 0 ? protocolExtra.WgMtu : Global.TunMtus.First(),
|
||||||
@@ -428,7 +428,7 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
kcpFinalmask.udp?.Reverse();
|
kcpFinalmask.udp?.Reverse();
|
||||||
streamSettings.kcpSettings = kcpSettings;
|
streamSettings.kcpSettings = kcpSettings;
|
||||||
streamSettings.finalmask = kcpFinalmask;
|
streamSettings.finalmask = (JsonObject)JsonUtils.SerializeToNode(kcpFinalmask);
|
||||||
break;
|
break;
|
||||||
//ws
|
//ws
|
||||||
case nameof(ETransport.ws):
|
case nameof(ETransport.ws):
|
||||||
@@ -489,7 +489,7 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
if (xhttpExtra.IsNotEmpty())
|
if (xhttpExtra.IsNotEmpty())
|
||||||
{
|
{
|
||||||
xhttpSettings.extra = JsonUtils.ParseJson(xhttpExtra);
|
xhttpSettings.extra = JsonUtils.ParseJson(xhttpExtra) as JsonObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
streamSettings.xhttpSettings = xhttpSettings;
|
streamSettings.xhttpSettings = xhttpSettings;
|
||||||
@@ -581,7 +581,7 @@ public partial class CoreConfigV2rayService
|
|||||||
auth = _node.Password,
|
auth = _node.Password,
|
||||||
};
|
};
|
||||||
hy2Finalmask.udp?.Reverse();
|
hy2Finalmask.udp?.Reverse();
|
||||||
streamSettings.finalmask = hy2Finalmask;
|
streamSettings.finalmask = (JsonObject)JsonUtils.SerializeToNode(hy2Finalmask);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "masque":
|
case "masque":
|
||||||
@@ -637,7 +637,7 @@ public partial class CoreConfigV2rayService
|
|||||||
pathHttp = string.Join(",".AppendQuotes(), arrPath);
|
pathHttp = string.Join(",".AppendQuotes(), arrPath);
|
||||||
}
|
}
|
||||||
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
|
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
|
||||||
rawSettings.header.request = JsonUtils.Deserialize<object>(request);
|
rawSettings.header.request = JsonUtils.SerializeToNode(request) as JsonObject;
|
||||||
|
|
||||||
streamSettings.rawSettings = rawSettings;
|
streamSettings.rawSettings = rawSettings;
|
||||||
}
|
}
|
||||||
@@ -646,7 +646,7 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
if (!_node.Finalmask.IsNullOrEmpty())
|
if (!_node.Finalmask.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
streamSettings.finalmask = JsonUtils.ParseJson(_node.Finalmask);
|
streamSettings.finalmask = JsonUtils.ParseJson(_node.Finalmask) as JsonObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -837,10 +837,10 @@ public partial class CoreConfigV2rayService
|
|||||||
protocol = "freedom",
|
protocol = "freedom",
|
||||||
streamSettings = new StreamSettings4Ray
|
streamSettings = new StreamSettings4Ray
|
||||||
{
|
{
|
||||||
finalmask = new Finalmask4Ray
|
finalmask = JsonUtils.SerializeToNode(new Finalmask4Ray
|
||||||
{
|
{
|
||||||
tcp = [fragmentMask],
|
tcp = [fragmentMask],
|
||||||
},
|
}) as JsonObject,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -335,9 +335,13 @@ public partial class UpdateService(Config config, Func<bool, string, Task> updat
|
|||||||
//Check for avalonia desktop windows version
|
//Check for avalonia desktop windows version
|
||||||
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "libHarfBuzzSharp.dll")))
|
if (File.Exists(Path.Combine(Utils.GetBaseDirectory(), "libHarfBuzzSharp.dll")))
|
||||||
{
|
{
|
||||||
return url?.Replace(".zip", "-desktop.zip");
|
url = url?.Replace(".zip", "-desktop.zip");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if V2RAYN_IS_AOT
|
||||||
|
url = url?.Replace(".zip", "-aot.zip");
|
||||||
|
#endif
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
else if (Utils.IsLinux())
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public sealed class WindowsJobService : IDisposable
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
|
var length = Marshal.SizeOf<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
|
||||||
extendedInfoPtr = Marshal.AllocHGlobal(length);
|
extendedInfoPtr = Marshal.AllocHGlobal(length);
|
||||||
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
|
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
|
||||||
|
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ public partial class ProfilesViewModel : MyReactiveObject
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var orderProfiles = SelectedProfiles?.OrderBy(t => t.Sort);
|
var orderProfiles = SelectedProfiles?.OrderBy(t => t.Sort).ToList();
|
||||||
if (latest)
|
if (latest)
|
||||||
{
|
{
|
||||||
lstSelected.AddRange(await AppManager.Instance.GetProfileItemsOrderedByIndexIds(orderProfiles.Select(sp => sp?.IndexId)));
|
lstSelected.AddRange(await AppManager.Instance.GetProfileItemsOrderedByIndexIds(orderProfiles.Select(sp => sp?.IndexId)));
|
||||||
@@ -712,7 +712,7 @@ public partial class ProfilesViewModel : MyReactiveObject
|
|||||||
actionType = ESpeedActionType.Realping;
|
actionType = ESpeedActionType.Realping;
|
||||||
}
|
}
|
||||||
|
|
||||||
lstSelected = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(ProfileItems?.OrderBy(t => t.Sort)));
|
lstSelected = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(ProfileItems?.OrderBy(t => t.Sort).ToList()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -191,13 +191,7 @@ public partial class RoutingRuleSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
}
|
}
|
||||||
if (lst.Count > 0)
|
if (lst.Count > 0)
|
||||||
{
|
{
|
||||||
var options = new JsonSerializerOptions
|
await SetClipboardDataInteraction.HandleSafe(JsonUtils.SerializeCamelCase(lst));
|
||||||
{
|
|
||||||
WriteIndented = true,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
};
|
|
||||||
await SetClipboardDataInteraction.HandleSafe(JsonUtils.Serialize(lst, options));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public partial class QRCodeAvaloniaUtils
|
|||||||
|
|
||||||
var bmi = new BITMAPINFO
|
var bmi = new BITMAPINFO
|
||||||
{
|
{
|
||||||
biSize = Marshal.SizeOf(typeof(BITMAPINFO)),
|
biSize = Marshal.SizeOf<BITMAPINFO>(),
|
||||||
biWidth = width,
|
biWidth = width,
|
||||||
biHeight = -height,
|
biHeight = -height,
|
||||||
biPlanes = 1,
|
biPlanes = 1,
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<linker>
|
||||||
|
<assembly fullname="ServiceLib">
|
||||||
|
<type fullname="ServiceLib.Models.*" preserve="all" />
|
||||||
|
<type fullname="ServiceLib.Enums.*" preserve="all" />
|
||||||
|
</assembly>
|
||||||
|
</linker>
|
||||||
@@ -7,8 +7,6 @@ namespace v2rayN.Desktop.Views;
|
|||||||
|
|
||||||
public partial class JsonEditor : UserControl
|
public partial class JsonEditor : UserControl
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerOptions SIndentedOptions = new() { WriteIndented = true };
|
|
||||||
|
|
||||||
private static readonly Lazy<IHighlightingDefinition> SHighlightingDark =
|
private static readonly Lazy<IHighlightingDefinition> SHighlightingDark =
|
||||||
new(() => BuildHighlighting(dark: true), isThreadSafe: true);
|
new(() => BuildHighlighting(dark: true), isThreadSafe: true);
|
||||||
|
|
||||||
@@ -88,7 +86,7 @@ public partial class JsonEditor : UserControl
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var obj = JsonUtils.ParseJson(Editor.Text);
|
var obj = JsonUtils.ParseJson(Editor.Text);
|
||||||
Editor.Text = JsonUtils.Serialize(obj, SIndentedOptions);
|
Editor.Text = JsonUtils.Serialize(obj, indented: true, nullValue: true);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,4 +56,7 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<TrimmerRootDescriptor Include="TrimmerRoots.xml" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user