diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index c68dbc68..c65e311d 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -29,6 +29,22 @@ jobs: release_tag: ${{ inputs.release_tag }} 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: 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/')) diff --git a/.github/workflows/build-osx.yml b/.github/workflows/build-osx.yml index 47b6dbe0..21a43d88 100644 --- a/.github/workflows/build-osx.yml +++ b/.github/workflows/build-osx.yml @@ -28,7 +28,23 @@ jobs: target: macos release_tag: ${{ inputs.release_tag }} 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: name: package and release macOS dmg if: inputs.release_tag != '' diff --git a/.github/workflows/build-windows-desktop.yml b/.github/workflows/build-windows-desktop.yml index a473b96b..92a9159f 100644 --- a/.github/workflows/build-windows-desktop.yml +++ b/.github/workflows/build-windows-desktop.yml @@ -28,3 +28,19 @@ jobs: target: windows-desktop release_tag: ${{ inputs.release_tag }} 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 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 114718a0..38a8d70c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,10 @@ on: required: false type: string default: './v2rayN.Desktop/v2rayN.Desktop.csproj' + isAot: + required: false + type: boolean + default: false jobs: build: @@ -27,7 +31,6 @@ jobs: ) }} env: - Output: "${{ github.workspace }}/${{ matrix.arch }}" RID: |- ${{ case( @@ -41,6 +44,7 @@ jobs: ${{ case( 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 uses: actions/setup-dotnet@v6 with: - dotnet-version: 10.0.1xx - - - name: Build v2rayN + dotnet-version: 10.0.x + + - name: Install dependencies shell: bash - working-directory: ./v2rayN - run: dotnet publish $Project -c Release -r $RID -p:SelfContained=true $ExtOpt -o $Output + if: inputs.target == 'linux' && inputs.isAot + 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 shell: bash 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 shell: bash 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 uses: actions/upload-artifact@v7 with: - name: ${{ matrix.arch }} - path: ${{ matrix.arch }} + name: ${{ matrix.arch }}${{ inputs.isAot && '-aot' || '' }} + path: ${{ env.OUTPUT }} diff --git a/.github/workflows/package-zip.yml b/.github/workflows/package-zip.yml index 3b6e7116..599261c9 100644 --- a/.github/workflows/package-zip.yml +++ b/.github/workflows/package-zip.yml @@ -9,6 +9,10 @@ on: target: # windows linux macos windows-desktop required: true type: string + isAot: + required: false + type: boolean + default: false secrets: GPG_PRIVATE_KEY: required: true @@ -43,27 +47,62 @@ jobs: - name: Checkout 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 uses: actions/download-artifact@v8 with: - name: ${{ matrix.arch }} - path: v2rayN-${{ env.Target }}-${{ env.Arch }} - + name: ${{ steps.package-vars.outputs.build_artifact_name }} + path: ${{ steps.package-vars.outputs.package_dir }} + - 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 - 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 package archive + if: steps.package-vars.outputs.rename_suffix != '' + shell: bash + run: | + mv "${{ steps.package-vars.outputs.package_file }}" \ + "${{ steps.package-vars.outputs.package_dir }}${{ steps.package-vars.outputs.rename_suffix }}.zip" - - name: Rename windows-desktop - if: inputs.target == 'windows-desktop' - run: mv "v2rayN-$Target-$Arch.zip" "v2rayN-$Target-$Arch-desktop.zip" - - name: Upload zip artifact uses: actions/upload-artifact@v7 with: - name: release-${{ inputs.target }}-${{ matrix.arch }} - path: v2rayN*.zip + name: release-${{ inputs.target }}-${{ matrix.arch }}${{ inputs.isAot && '-aot' || '' }} + path: ${{ steps.package-vars.outputs.final_package_file }} if-no-files-found: error release: @@ -75,7 +114,7 @@ jobs: uses: ./.github/workflows/upload-sign.yml with: 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' secrets: GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} diff --git a/v2rayN/AmazTool/AmazTool.csproj b/v2rayN/AmazTool/AmazTool.csproj index 4657a889..9cdd5f89 100644 --- a/v2rayN/AmazTool/AmazTool.csproj +++ b/v2rayN/AmazTool/AmazTool.csproj @@ -5,16 +5,31 @@ - - ResXFileCodeGenerator - Resource.Designer.cs - - True True Resource.resx + + Designer + Resource.Designer.cs + ResXFileCodeGenerator + + + Designer + ResXFileCodeGenerator + + + Designer + ResXFileCodeGenerator + + + + + + + \ No newline at end of file diff --git a/v2rayN/AmazTool/Resx/Resource.Designer.cs b/v2rayN/AmazTool/Resx/Resource.Designer.cs index 2283298a..7cca6bdc 100644 --- a/v2rayN/AmazTool/Resx/Resource.Designer.cs +++ b/v2rayN/AmazTool/Resx/Resource.Designer.cs @@ -19,7 +19,7 @@ namespace AmazTool.Resx { // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /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.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resource { diff --git a/v2rayN/Directory.Build.props b/v2rayN/Directory.Build.props index 19b4e76c..dfbd4fca 100644 --- a/v2rayN/Directory.Build.props +++ b/v2rayN/Directory.Build.props @@ -29,4 +29,14 @@ true false + + + false + + + + true + true + $(DefineConstants);V2RAYN_IS_AOT + diff --git a/v2rayN/Directory.Packages.props b/v2rayN/Directory.Packages.props index 992e02f6..292b44f7 100644 --- a/v2rayN/Directory.Packages.props +++ b/v2rayN/Directory.Packages.props @@ -25,8 +25,7 @@ - - + diff --git a/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj b/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj index 2dd3c7a3..98c31aa6 100644 --- a/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj +++ b/v2rayN/ServiceLib.Tests/ServiceLib.Tests.csproj @@ -4,6 +4,7 @@ Exe false enable + true diff --git a/v2rayN/ServiceLib/Common/JsonUtils.cs b/v2rayN/ServiceLib/Common/JsonUtils.cs index 951cdbd7..6aa22381 100644 --- a/v2rayN/ServiceLib/Common/JsonUtils.cs +++ b/v2rayN/ServiceLib/Common/JsonUtils.cs @@ -7,40 +7,45 @@ public class JsonUtils private static readonly JsonSerializerOptions _defaultDeserializeOptions = new() { PropertyNameCaseInsensitive = true, - ReadCommentHandling = JsonCommentHandling.Skip + ReadCommentHandling = JsonCommentHandling.Skip, + TypeInfoResolver = AppJsonContext.Default, }; private static readonly JsonSerializerOptions _defaultSerializeOptions = new() { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + TypeInfoResolver = AppJsonContext.Default, }; private static readonly JsonSerializerOptions _defaultSerializeNoIndentedOptions = new() { WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + TypeInfoResolver = AppJsonContext.Default, }; private static readonly JsonSerializerOptions _nullValueSerializeOptions = new() { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + TypeInfoResolver = AppJsonContext.Default, }; private static readonly JsonSerializerOptions _nullValueSerializeNoIndentedOptions = new() { WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + TypeInfoResolver = AppJsonContext.Default, }; private static readonly JsonDocumentOptions _defaultDocumentOptions = new() { - CommentHandling = JsonCommentHandling.Skip + CommentHandling = JsonCommentHandling.Skip, }; /// @@ -109,7 +114,7 @@ public class JsonUtils /// /// /// - public static string Serialize(object? obj, bool indented = true, bool nullValue = false) + public static string Serialize(T? obj, bool indented = true, bool nullValue = false) { var result = string.Empty; try @@ -140,7 +145,7 @@ public class JsonUtils /// /// /// - public static string Serialize(object? obj, JsonSerializerOptions? options) + public static string SerializeCamelCase(T? obj) { var result = string.Empty; try @@ -149,7 +154,14 @@ public class JsonUtils { 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) { @@ -162,9 +174,108 @@ public class JsonUtils /// SerializeToNode /// /// + /// /// - public static JsonNode? SerializeToNode(object? obj, JsonSerializerOptions? options = null) + public static JsonNode? SerializeToNode(T? obj, bool nullValue = false) { + var options = nullValue ? _nullValueSerializeOptions : _defaultSerializeOptions; return JsonSerializer.SerializeToNode(obj, options); } + + public static JsonArray? SerializeToArray(IEnumerable? 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))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(ProfileItemModel))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(RoutingTemplate))] +[JsonSerializable(typeof(DNSItem))] +[JsonSerializable(typeof(SimpleDNSItem))] +[JsonSerializable(typeof(IPAPIInfo))] +[JsonSerializable(typeof(SsSIP008))] +[JsonSerializable(typeof(List))] +[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))] +[JsonSerializable(typeof(ServerStatItem))] +[JsonSerializable(typeof(WebDavItem))] +[JsonSerializable(typeof(KeyEventItem))] +[JsonSerializable(typeof(SubItem))] +[JsonSerializable(typeof(SingboxConfig))] +[JsonSerializable(typeof(Dns4Sbox))] +[JsonSerializable(typeof(Inbound4Sbox))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(Endpoints4Sbox))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(Outbound4Sbox))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(Rule4Sbox))] +[JsonSerializable(typeof(Ruleset4Sbox))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(V2rayConfig))] +[JsonSerializable(typeof(Dns4Ray))] +[JsonSerializable(typeof(DnsServer4Ray))] +[JsonSerializable(typeof(Inbounds4Ray))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(Outbounds4Ray))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(RulesItem4Ray))] +[JsonSerializable(typeof(List))] +[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))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(Dictionary))] +[JsonSerializable(typeof(object))] +[JsonSerializable(typeof(JsonElement))] +[JsonSerializable(typeof(JsonDocument))] +[JsonSerializable(typeof(JsonNode))] +[JsonSerializable(typeof(JsonObject))] +[JsonSerializable(typeof(JsonArray))] +internal partial class AppJsonContext : JsonSerializerContext; diff --git a/v2rayN/ServiceLib/Common/Utils.cs b/v2rayN/ServiceLib/Common/Utils.cs index 393c4fe7..66b735d8 100644 --- a/v2rayN/ServiceLib/Common/Utils.cs +++ b/v2rayN/ServiceLib/Common/Utils.cs @@ -348,10 +348,9 @@ public class Utils .ToList()); } - public static List GetEnumNames() where TEnum : Enum + public static List GetEnumNames() where TEnum : struct, Enum { - return Enum.GetValues(typeof(TEnum)) - .Cast() + return Enum.GetValues() .Select(e => e.ToString()) .ToList(); } diff --git a/v2rayN/ServiceLib/Common/YamlUtils.cs b/v2rayN/ServiceLib/Common/YamlUtils.cs index a95e1b0a..f1b94890 100644 --- a/v2rayN/ServiceLib/Common/YamlUtils.cs +++ b/v2rayN/ServiceLib/Common/YamlUtils.cs @@ -1,6 +1,5 @@ using YamlDotNet.Core; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.NamingConventions; +using YamlDotNet.RepresentationModel; namespace ServiceLib.Common; @@ -13,45 +12,57 @@ public class YamlUtils /// /// Deserialize /// - /// /// /// - public static T FromYaml(string str) + public static YamlMappingNode FromYaml(string str) { - var deserializer = new DeserializerBuilder() - .WithNamingConvention(PascalCaseNamingConvention.Instance) - .Build(); + //var deserializer = new DeserializerBuilder() + // .WithNamingConvention(PascalCaseNamingConvention.Instance) + // .Build(); + //try + //{ + // var obj = deserializer.Deserialize(str); + // return obj; + //} + //catch (Exception ex) + //{ + // Logging.SaveLog(_tag, ex); + // return deserializer.Deserialize(""); + //} try { - var obj = deserializer.Deserialize(str); - return obj; + var yaml = new YamlStream(); + using var reader = new StringReader(str); + yaml.Load(reader); + var rootNode = (YamlMappingNode)yaml.Documents[0].RootNode; + return rootNode; } catch (Exception ex) { Logging.SaveLog(_tag, ex); - return deserializer.Deserialize(""); + return new YamlMappingNode(); } } /// /// Serialize /// - /// + /// /// - public static string ToYaml(object? obj) + public static string ToYaml(YamlMappingNode? node) { var result = string.Empty; - if (obj == null) + if (node == null) { return result; } - var serializer = new SerializerBuilder() - .WithNamingConvention(HyphenatedNamingConvention.Instance) - .Build(); - 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) { @@ -64,9 +75,15 @@ public class YamlUtils { try { - var mergingParser = new MergingParser(new Parser(new StringReader(str))); - var obj = new DeserializerBuilder().Build().Deserialize(mergingParser); - return ToYaml(obj); + using var reader = new StringReader(str); + var parser = new Parser(reader); + 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) { diff --git a/v2rayN/ServiceLib/Global.cs b/v2rayN/ServiceLib/Global.cs index eaedc701..6159013d 100644 --- a/v2rayN/ServiceLib/Global.cs +++ b/v2rayN/ServiceLib/Global.cs @@ -42,6 +42,7 @@ public class Global public const string SingboxFakeIPFilterFileName = NamespaceSample + "singbox_fakeip_filter"; public const string ChromeRootCertFileName = NamespaceSample + "chrome_roots_pem"; public const string MozillaRootCertFileName = NamespaceSample + "mozilla_roots_pem"; + public const string TaskXmlTemplateFileName = NamespaceSample + "TaskXmlTemplate"; public const string ChromeRootProvider = "chrome"; public const string MozillaRootProvider = "mozilla"; diff --git a/v2rayN/ServiceLib/Handler/AutoStartupHandler.cs b/v2rayN/ServiceLib/Handler/AutoStartupHandler.cs index acd9a515..c1259456 100644 --- a/v2rayN/ServiceLib/Handler/AutoStartupHandler.cs +++ b/v2rayN/ServiceLib/Handler/AutoStartupHandler.cs @@ -87,6 +87,7 @@ public static class AutoStartupHandler [SupportedOSPlatform("windows")] public static void AutoStartTaskService(string taskName, string fileName, string description) { +#if false if (taskName.IsNullOrEmpty()) { return; @@ -117,6 +118,78 @@ public static class AutoStartupHandler task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName))); 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() diff --git a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs index 58be1d37..898becd2 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/BaseFmt.cs @@ -80,12 +80,7 @@ public class BaseFmt { var node = JsonUtils.ParseJson(item.Finalmask); var finalmask = node != null - ? JsonUtils.Serialize(node, new JsonSerializerOptions - { - WriteIndented = false, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }) + ? JsonUtils.Serialize(node, indented: false, nullValue: true) : item.Finalmask; dicQuery.Add("fm", Utils.UrlEncode(finalmask)); } @@ -154,12 +149,7 @@ public class BaseFmt { var node = JsonUtils.ParseJson(transport.XhttpExtra); var extra = node != null - ? JsonUtils.Serialize(node, new JsonSerializerOptions - { - WriteIndented = false, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }) + ? JsonUtils.Serialize(node, indented: false, nullValue: true) : transport.XhttpExtra; dicQuery.Add("extra", UrlEncodeSafe(extra)); } @@ -215,12 +205,7 @@ public class BaseFmt { var node = JsonUtils.ParseJson(finalmaskDecoded); item.Finalmask = node != null - ? JsonUtils.Serialize(node, new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }) + ? JsonUtils.Serialize(node, indented: true, nullValue: true) : finalmaskDecoded; } else @@ -278,12 +263,7 @@ public class BaseFmt var node = JsonUtils.ParseJson(xhttpExtra); if (node != null) { - xhttpExtra = JsonUtils.Serialize(node, new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }); + xhttpExtra = JsonUtils.Serialize(node, indented: true, nullValue: true); } } diff --git a/v2rayN/ServiceLib/Handler/Fmt/InnerFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/InnerFmt.cs index c39ab032..752bddf4 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/InnerFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/InnerFmt.cs @@ -179,12 +179,7 @@ public class InnerFmt : BaseFmt if (jsonObj.TryGetPropertyValue("CustomOutboundObj", out var customOutboundNode) && customOutboundNode is JsonObject customOutboundObj) { - var customOutboundContent = JsonUtils.Serialize(customOutboundObj, new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }); + var customOutboundContent = JsonUtils.Serialize(customOutboundObj, indented: true, nullValue: true); customOutboundFilePath = WriteAllText(customOutboundContent); jsonObj.Remove("CustomOutboundObj"); } diff --git a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs index dfd0408b..126ea3ba 100644 --- a/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs +++ b/v2rayN/ServiceLib/Handler/Fmt/WireguardFmt.cs @@ -29,12 +29,7 @@ public class WireguardFmt : BaseFmt { var node = JsonUtils.ParseJson(finalmaskDecoded); item.Finalmask = node != null - ? JsonUtils.Serialize(node, new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }) + ? JsonUtils.Serialize(node, indented: true, nullValue: true) : finalmaskDecoded; } else @@ -98,12 +93,7 @@ public class WireguardFmt : BaseFmt { var node = JsonUtils.ParseJson(item.Finalmask); var finalmask = node != null - ? JsonUtils.Serialize(node, new JsonSerializerOptions - { - WriteIndented = false, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }) + ? JsonUtils.Serialize(node, indented: false, nullValue: true) : item.Finalmask; dicQuery.Add("fm", Utils.UrlEncode(finalmask)); } diff --git a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingWindows.cs b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingWindows.cs index 614437d7..d3738644 100644 --- a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingWindows.cs +++ b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingWindows.cs @@ -133,7 +133,7 @@ public static class ProxySettingWindows list.dwOptionCount = options.Length; list.dwOptionError = 0; - var optSize = Marshal.SizeOf(typeof(InternetConnectionOption)); + var optSize = Marshal.SizeOf(); // make a pointer out of all that ... var optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4 // copy the array over into that spot in memory ... @@ -207,17 +207,17 @@ public static class ProxySettingWindows var entries = 0; // attempt to query with 1 entry buffer var rasEntryNames = new RASENTRYNAME[1]; - var bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME)); - rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME)); + var bufferSize = Marshal.SizeOf(); + rasEntryNames[0].dwSize = Marshal.SizeOf(); var result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries); // increase buffer if the buffer is not large enough if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL) { - rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))]; + rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf()]; for (var i = 0; i < rasEntryNames.Length; i++) { - rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME)); + rasEntryNames[i].dwSize = Marshal.SizeOf(); } result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries); @@ -258,7 +258,7 @@ public static class ProxySettingWindows static InternetConnectionOption() { - Size = Marshal.SizeOf(typeof(InternetConnectionOption)); + Size = Marshal.SizeOf(); } // Nested Types diff --git a/v2rayN/ServiceLib/Models/Configs/Config.cs b/v2rayN/ServiceLib/Models/Configs/Config.cs index 834a13a9..61ef2e91 100644 --- a/v2rayN/ServiceLib/Models/Configs/Config.cs +++ b/v2rayN/ServiceLib/Models/Configs/Config.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Configs; -[Serializable] public class Config { #region property diff --git a/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs b/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs index 4219b66e..54c91fc4 100644 --- a/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Configs; -[Serializable] public class CoreBasicItem { public bool LogEnabled { get; set; } @@ -22,7 +21,6 @@ public class CoreBasicItem public bool EnableCacheFile4Sbox { get; set; } = true; } -[Serializable] public class InItem { public int LocalPort { get; set; } @@ -38,7 +36,6 @@ public class InItem public bool SecondLocalPortEnabled { get; set; } } -[Serializable] public class KcpItem { public int Mtu { get; set; } @@ -54,7 +51,6 @@ public class KcpItem public int MaxSendingWindow { get; set; } } -[Serializable] public class GrpcItem { public int? IdleTimeout { get; set; } @@ -63,7 +59,6 @@ public class GrpcItem public int? InitialWindowsSize { get; set; } } -[Serializable] public class GUIItem { public bool AutoRun { get; set; } @@ -77,14 +72,12 @@ public class GUIItem public string? RootCertProvider { get; set; } } -[Serializable] public class MsgUIItem { public string? MainMsgFilter { get; set; } public bool? AutoRefresh { get; set; } } -[Serializable] public class UIItem { public bool EnableAutoAdjustMainLvColWidth { get; set; } @@ -106,7 +99,6 @@ public class UIItem public bool HideColumnIpInfo { get; set; } } -[Serializable] public class ConstItem { public string? SubConvertUrl { get; set; } @@ -115,7 +107,6 @@ public class ConstItem public string? RouteRulesTemplateSourceUrl { get; set; } } -[Serializable] public class KeyEventItem { public EGlobalHotkey EGlobalHotkey { get; set; } @@ -129,7 +120,6 @@ public class KeyEventItem public int? KeyCode { get; set; } } -[Serializable] public class CoreTypeItem { public EConfigType ConfigType { get; set; } @@ -137,7 +127,6 @@ public class CoreTypeItem public ECoreType CoreType { get; set; } } -[Serializable] public class TunModeItem { public bool EnableTun { get; set; } @@ -153,7 +142,6 @@ public class TunModeItem public string IPv6Address { get; set; } } -[Serializable] public class SpeedTestItem { public int SpeedTestTimeout { get; set; } @@ -166,7 +154,6 @@ public class SpeedTestItem public int? SpeedTestDelayInterval { get; set; } } -[Serializable] public class RoutingBasicItem { public string DomainStrategy { get; set; } @@ -174,7 +161,6 @@ public class RoutingBasicItem public string RoutingIndexId { get; set; } } -[Serializable] public class ColumnItem { public string Name { get; set; } @@ -182,7 +168,6 @@ public class ColumnItem public int Index { get; set; } } -[Serializable] public class Mux4RayItem { public int? Concurrency { get; set; } @@ -190,7 +175,6 @@ public class Mux4RayItem public string? XudpProxyUDP443 { get; set; } } -[Serializable] public class Mux4SboxItem { public string Protocol { get; set; } @@ -198,7 +182,6 @@ public class Mux4SboxItem public bool? Padding { get; set; } } -[Serializable] public class HysteriaItem { public int UpMbps { get; set; } @@ -206,7 +189,6 @@ public class HysteriaItem public int HopInterval { get; set; } = Global.Hysteria2DefaultHopInt; } -[Serializable] public class ClashUIItem { public bool EnableIPv6 { get; set; } @@ -219,7 +201,6 @@ public class ClashUIItem public List ConnectionsColumnItem { get; set; } } -[Serializable] public class SystemProxyItem { public ESysProxyType SysProxyType { get; set; } @@ -230,7 +211,6 @@ public class SystemProxyItem public string? CustomSystemProxyScriptPath { get; set; } } -[Serializable] public class WebDavItem { public string? Url { get; set; } @@ -239,7 +219,6 @@ public class WebDavItem public string? DirName { get; set; } } -[Serializable] public class CheckUpdateItem { public bool UpdateViaProxy { get; set; } = true; @@ -247,7 +226,6 @@ public class CheckUpdateItem public List? CheckPreReleaseCoreTypes { get; set; } } -[Serializable] public class Fragment4RayItem { public string? Packets { get; set; } @@ -262,7 +240,6 @@ public class Fragment4RayItem // migration end } -[Serializable] public class WindowSizeItem { public string TypeName { get; set; } @@ -270,7 +247,6 @@ public class WindowSizeItem public int Height { get; set; } } -[Serializable] public class SimpleDNSItem { public bool? UseSystemHosts { get; set; } @@ -293,7 +269,6 @@ public class SimpleDNSItem public bool? EnableHappyEyeballs { get; set; } } -[Serializable] public class HappyEyeballs4RayItem { public int? TryDelayMs { get; set; } diff --git a/v2rayN/ServiceLib/Models/CoreConfigs/CoreInfo.cs b/v2rayN/ServiceLib/Models/CoreConfigs/CoreInfo.cs index df5f3667..8bc886ce 100644 --- a/v2rayN/ServiceLib/Models/CoreConfigs/CoreInfo.cs +++ b/v2rayN/ServiceLib/Models/CoreConfigs/CoreInfo.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.CoreConfigs; -[Serializable] public class CoreInfo { public ECoreType CoreType { get; set; } diff --git a/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs b/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs index e77b4640..6e549d1a 100644 --- a/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs +++ b/v2rayN/ServiceLib/Models/CoreConfigs/SingboxConfig.cs @@ -44,7 +44,6 @@ public class Route4Sbox public string? final { get; set; } } -[Serializable] public class Rule4Sbox { public string? outbound { get; set; } @@ -103,7 +102,6 @@ public class Rule4Sbox public bool? speculative { get; set; } } -[Serializable] public class Inbound4Sbox { public string type { get; set; } @@ -232,7 +230,7 @@ public class Reality4Sbox public class Transport4Sbox { public string? type { get; set; } - public object? host { get; set; } + public JsonNode? host { get; set; } public string? path { get; set; } public Headers4Sbox? headers { get; set; } diff --git a/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs b/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs index 5978e79f..a56a3fe0 100644 --- a/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs +++ b/v2rayN/ServiceLib/Models/CoreConfigs/V2rayConfig.cs @@ -3,7 +3,7 @@ namespace ServiceLib.Models.CoreConfigs; public class V2rayConfig { public Log4Ray log { get; set; } - public object dns { get; set; } + public JsonObject? dns { get; set; } public FakeDns4Ray? fakedns { get; set; } public List inbounds { get; set; } public List outbounds { get; set; } @@ -130,7 +130,7 @@ public class Outboundsettings4Ray public string? secretKey { get; set; } - public object? address { get; set; } + public JsonNode? address { get; set; } public int? port { get; set; } @@ -142,7 +142,7 @@ public class Outboundsettings4Ray public string? email { get; set; } - public object? headers { get; set; } + public JsonNode? headers { get; set; } public List? peers { get; set; } @@ -199,8 +199,8 @@ public class Response4Ray public class Dns4Ray { - public Dictionary? hosts { get; set; } - public List servers { get; set; } + public Dictionary? hosts { get; set; } + public List servers { get; set; } public bool? serveStale { get; set; } public bool? enableParallelQuery { get; set; } public string? queryStrategy { get; set; } @@ -226,7 +226,6 @@ public class Routing4Ray public List? balancers { get; set; } } -[Serializable] public class RulesItem4Ray { public string? type { get; set; } @@ -321,7 +320,7 @@ public class StreamSettings4Ray public HysteriaSettings4Ray? hysteriaSettings { get; set; } public MasqueSettings4Ray? masqueSettings { get; set; } - public object? finalmask { get; set; } + public JsonObject? finalmask { get; set; } public Sockopt4Ray? sockopt { get; set; } } @@ -363,9 +362,9 @@ public class Header4Ray { 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 @@ -411,7 +410,7 @@ public class XhttpSettings4Ray public string? path { get; set; } public string? host { get; set; } public string? mode { get; set; } - public object? extra { get; set; } + public JsonObject? extra { get; set; } } public class HttpSettings4Ray diff --git a/v2rayN/ServiceLib/Models/Dto/ClashProxyModel.cs b/v2rayN/ServiceLib/Models/Dto/ClashProxyModel.cs index d4602c65..5b37ffaa 100644 --- a/v2rayN/ServiceLib/Models/Dto/ClashProxyModel.cs +++ b/v2rayN/ServiceLib/Models/Dto/ClashProxyModel.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public partial class ClashProxyModel : ReactiveObject { public string Name { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/ProfileItemModel.cs b/v2rayN/ServiceLib/Models/Dto/ProfileItemModel.cs index ade4277c..e9e71ee2 100644 --- a/v2rayN/ServiceLib/Models/Dto/ProfileItemModel.cs +++ b/v2rayN/ServiceLib/Models/Dto/ProfileItemModel.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public partial class ProfileItemModel : ReactiveObject { public bool IsActive { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/RoutingItemModel.cs b/v2rayN/ServiceLib/Models/Dto/RoutingItemModel.cs index 2abde924..b8ba92c7 100644 --- a/v2rayN/ServiceLib/Models/Dto/RoutingItemModel.cs +++ b/v2rayN/ServiceLib/Models/Dto/RoutingItemModel.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public class RoutingItemModel : RoutingItem { } diff --git a/v2rayN/ServiceLib/Models/Dto/RoutingTemplate.cs b/v2rayN/ServiceLib/Models/Dto/RoutingTemplate.cs index 0d3fd808..cda5b5e1 100644 --- a/v2rayN/ServiceLib/Models/Dto/RoutingTemplate.cs +++ b/v2rayN/ServiceLib/Models/Dto/RoutingTemplate.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public class RoutingTemplate { public string Version { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/RulesItemModel.cs b/v2rayN/ServiceLib/Models/Dto/RulesItemModel.cs index b056f47c..0ce3e0a3 100644 --- a/v2rayN/ServiceLib/Models/Dto/RulesItemModel.cs +++ b/v2rayN/ServiceLib/Models/Dto/RulesItemModel.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public class RulesItemModel : RulesItem { public string InboundTags { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/ServerSpeedItem.cs b/v2rayN/ServiceLib/Models/Dto/ServerSpeedItem.cs index 3d9e7562..6a8c464d 100644 --- a/v2rayN/ServiceLib/Models/Dto/ServerSpeedItem.cs +++ b/v2rayN/ServiceLib/Models/Dto/ServerSpeedItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public class ServerSpeedItem : ServerStatItem { public long ProxyUp { get; set; } @@ -12,7 +11,6 @@ public class ServerSpeedItem : ServerStatItem public long DirectDown { get; set; } } -[Serializable] public class TrafficItem { public ulong Up { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/ServerTestItem.cs b/v2rayN/ServiceLib/Models/Dto/ServerTestItem.cs index 66d33255..cc20cb58 100644 --- a/v2rayN/ServiceLib/Models/Dto/ServerTestItem.cs +++ b/v2rayN/ServiceLib/Models/Dto/ServerTestItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public class ServerTestItem { public string? IndexId { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/SpeedTestResult.cs b/v2rayN/ServiceLib/Models/Dto/SpeedTestResult.cs index 2e0ab1a5..cb835873 100644 --- a/v2rayN/ServiceLib/Models/Dto/SpeedTestResult.cs +++ b/v2rayN/ServiceLib/Models/Dto/SpeedTestResult.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Dto; -[Serializable] public class SpeedTestResult { public string? IndexId { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/SsSIP008.cs b/v2rayN/ServiceLib/Models/Dto/SsSIP008.cs index d6f05faf..73b7bcf8 100644 --- a/v2rayN/ServiceLib/Models/Dto/SsSIP008.cs +++ b/v2rayN/ServiceLib/Models/Dto/SsSIP008.cs @@ -5,7 +5,6 @@ public class SsSIP008 public List? servers { get; set; } } -[Serializable] public class SsServer { public string? remarks { get; set; } diff --git a/v2rayN/ServiceLib/Models/Dto/VmessQRCode.cs b/v2rayN/ServiceLib/Models/Dto/VmessQRCode.cs index bfb1408b..78847170 100644 --- a/v2rayN/ServiceLib/Models/Dto/VmessQRCode.cs +++ b/v2rayN/ServiceLib/Models/Dto/VmessQRCode.cs @@ -3,7 +3,6 @@ namespace ServiceLib.Models.Dto; /// /// https://github.com/2dust/v2rayN/wiki/ /// -[Serializable] public class VmessQRCode { [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] diff --git a/v2rayN/ServiceLib/Models/Entities/DNSItem.cs b/v2rayN/ServiceLib/Models/Entities/DNSItem.cs index 4bb4f65a..873f9ae1 100644 --- a/v2rayN/ServiceLib/Models/Entities/DNSItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/DNSItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class DNSItem { [PrimaryKey] diff --git a/v2rayN/ServiceLib/Models/Entities/FullConfigTemplateItem.cs b/v2rayN/ServiceLib/Models/Entities/FullConfigTemplateItem.cs index c51aa55e..15645532 100644 --- a/v2rayN/ServiceLib/Models/Entities/FullConfigTemplateItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/FullConfigTemplateItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class FullConfigTemplateItem { [PrimaryKey] diff --git a/v2rayN/ServiceLib/Models/Entities/ProfileExItem.cs b/v2rayN/ServiceLib/Models/Entities/ProfileExItem.cs index 85d1d536..6f8d9f22 100644 --- a/v2rayN/ServiceLib/Models/Entities/ProfileExItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/ProfileExItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class ProfileExItem { [PrimaryKey] diff --git a/v2rayN/ServiceLib/Models/Entities/ProfileGroupItem.cs b/v2rayN/ServiceLib/Models/Entities/ProfileGroupItem.cs index 6a878a50..26f40c19 100644 --- a/v2rayN/ServiceLib/Models/Entities/ProfileGroupItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/ProfileGroupItem.cs @@ -1,7 +1,6 @@ namespace ServiceLib.Models.Entities; [Obsolete("Use ProtocolExtraItem instead.")] -[Serializable] public class ProfileGroupItem { [PrimaryKey] diff --git a/v2rayN/ServiceLib/Models/Entities/ProfileItem.cs b/v2rayN/ServiceLib/Models/Entities/ProfileItem.cs index 375f43f6..82ff36de 100644 --- a/v2rayN/ServiceLib/Models/Entities/ProfileItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/ProfileItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class ProfileItem { private ProtocolExtraItem? _protocolExtraCache; diff --git a/v2rayN/ServiceLib/Models/Entities/RoutingItem.cs b/v2rayN/ServiceLib/Models/Entities/RoutingItem.cs index fae611e7..06bd9af8 100644 --- a/v2rayN/ServiceLib/Models/Entities/RoutingItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/RoutingItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class RoutingItem { [PrimaryKey] diff --git a/v2rayN/ServiceLib/Models/Entities/RulesItem.cs b/v2rayN/ServiceLib/Models/Entities/RulesItem.cs index 5c7c07d8..5979bf5e 100644 --- a/v2rayN/ServiceLib/Models/Entities/RulesItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/RulesItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class RulesItem { public string Id { get; set; } diff --git a/v2rayN/ServiceLib/Models/Entities/ServerStatItem.cs b/v2rayN/ServiceLib/Models/Entities/ServerStatItem.cs index a693fa4e..d2e4c80c 100644 --- a/v2rayN/ServiceLib/Models/Entities/ServerStatItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/ServerStatItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class ServerStatItem { [PrimaryKey] diff --git a/v2rayN/ServiceLib/Models/Entities/SubItem.cs b/v2rayN/ServiceLib/Models/Entities/SubItem.cs index cbaf6dcd..d490292e 100644 --- a/v2rayN/ServiceLib/Models/Entities/SubItem.cs +++ b/v2rayN/ServiceLib/Models/Entities/SubItem.cs @@ -1,6 +1,5 @@ namespace ServiceLib.Models.Entities; -[Serializable] public class SubItem { [PrimaryKey] diff --git a/v2rayN/ServiceLib/Sample/TaskXmlTemplate b/v2rayN/ServiceLib/Sample/TaskXmlTemplate new file mode 100644 index 00000000..f469dbbf --- /dev/null +++ b/v2rayN/ServiceLib/Sample/TaskXmlTemplate @@ -0,0 +1,24 @@ + + + + {{DESCRIPTION}} + + + + true + + + + + InteractiveToken + HighestAvailable + + + + + {{EXEC_PATH}} + {{ARGUMENTS}} + {{WORKING_DIRECTORY}} + + + \ No newline at end of file diff --git a/v2rayN/ServiceLib/ServiceLib.csproj b/v2rayN/ServiceLib/ServiceLib.csproj index b66c9eec..6fd8cee9 100644 --- a/v2rayN/ServiceLib/ServiceLib.csproj +++ b/v2rayN/ServiceLib/ServiceLib.csproj @@ -1,4 +1,4 @@ - + Library @@ -18,7 +18,6 @@ - @@ -45,6 +44,7 @@ + diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigClashService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigClashService.cs index a8103e99..96013109 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigClashService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigClashService.cs @@ -61,10 +61,10 @@ public class CoreConfigClashService(Config config, bool isTunEnabled) //YAML anchors if (txtFile.Contains("<<:") && txtFile.Contains('*') && txtFile.Contains('&')) { - txtFile = YamlUtils.PreprocessYaml(txtFile); + txtFile = YamlUtils.PreprocessYaml(txtFile) ?? ""; } - var fileContent = YamlUtils.FromYaml>(txtFile); + var fileContent = YamlUtils.FromYaml(txtFile); if (fileContent == null) { ret.Msg = ResUI.FailedConversionConfiguration; @@ -72,29 +72,38 @@ public class CoreConfigClashService(Config config, bool isTunEnabled) } //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 - 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 - fileContent["external-controller"] = $"{Global.Loopback}:{AppManager.Instance.StatePort2}"; - fileContent.Remove("secret"); + //fileContent["external-controller"] = $"{Global.Loopback}:{AppManager.Instance.StatePort2}"; + fileContent.Children[new YamlScalarNode("external-controller")] = new YamlScalarNode($"{Global.Loopback}:{AppManager.Instance.StatePort2}"); + //fileContent.Remove("secret"); + fileContent.Children.Remove(new YamlScalarNode("secret")); //allow-lan if (config.Inbound.First().AllowLANConn) { - fileContent["allow-lan"] = "true"; - fileContent["bind-address"] = "*"; + //fileContent["allow-lan"] = "true"; + fileContent.Children[new YamlScalarNode("allow-lan")] = new YamlScalarNode("true"); + //fileContent["bind-address"] = "*"; + fileContent.Children[new YamlScalarNode("bind-address")] = new YamlScalarNode("*"); } else { - fileContent["allow-lan"] = "false"; + //fileContent["allow-lan"] = "false"; + fileContent.Children[new YamlScalarNode("allow-lan")] = new YamlScalarNode("false"); } //ipv6 - fileContent["ipv6"] = config.ClashUIItem.EnableIPv6; + //fileContent["ipv6"] = config.ClashUIItem.EnableIPv6; + fileContent.Children[new YamlScalarNode("ipv6")] = new YamlScalarNode(config.ClashUIItem.EnableIPv6.ToString().ToLowerInvariant()); //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 if (isTunEnabled) @@ -102,10 +111,11 @@ public class CoreConfigClashService(Config config, bool isTunEnabled) var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml); if (tun.IsNotEmpty()) { - var tunContent = YamlUtils.FromYaml>(tun); + var tunContent = YamlUtils.FromYaml(tun); 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); } - // Mihomo parses plain values such as 815458e4 as floats, so quote REALITY short IDs. - var originalRealityShortIds = new List<(Dictionary RealityOptions, string ShortId)>(); - if (fileContent.GetValueOrDefault("proxies") is List proxies) - { - foreach (var proxy in proxies.OfType>()) - { - if (proxy.GetValueOrDefault("reality-opts") is Dictionary realityOptions - && realityOptions.GetValueOrDefault("short-id") is string shortId - && !shortId.StartsWith(tagYamlStr2, StringComparison.Ordinal)) - { - originalRealityShortIds.Add((realityOptions, shortId)); - realityOptions["short-id"] = new YamlScalarNode(shortId) { Style = ScalarStyle.DoubleQuoted }; - } - } - } + //// Mihomo parses plain values such as 815458e4 as floats, so quote REALITY short IDs. + //var originalRealityShortIds = new List<(Dictionary RealityOptions, string ShortId)>(); + //if (fileContent.GetValueOrDefault("proxies") is List proxies) + //{ + // foreach (var proxy in proxies.OfType>()) + // { + // if (proxy.GetValueOrDefault("reality-opts") is Dictionary realityOptions + // && realityOptions.GetValueOrDefault("short-id") is string shortId + // && !shortId.StartsWith(tagYamlStr2, StringComparison.Ordinal)) + // { + // originalRealityShortIds.Add((realityOptions, shortId)); + // realityOptions["short-id"] = new YamlScalarNode(shortId) { Style = ScalarStyle.DoubleQuoted }; + // } + // } + //} var txtFileNew = YamlUtils.ToYaml(fileContent).Replace(tagYamlStr2, tagYamlStr3); - foreach (var (realityOptions, shortId) in originalRealityShortIds) - { - realityOptions["short-id"] = shortId; - } + //foreach (var (realityOptions, shortId) in originalRealityShortIds) + //{ + // realityOptions["short-id"] = shortId; + //} await File.WriteAllTextAsync(fileName, txtFileNew); //check again if (!File.Exists(fileName)) @@ -161,7 +171,7 @@ public class CoreConfigClashService(Config config, bool isTunEnabled) } } - private async Task MixinContent(Dictionary fileContent, ProfileItem node) + private async Task MixinContent(YamlMappingNode fileContent, ProfileItem node) { 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 mixinContent = YamlUtils.FromYaml>(txtFile); + var mixinContent = YamlUtils.FromYaml(txtFile); if (mixinContent == null) { 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; } - if (item.Key.StartsWith("prepend-") - || item.Key.StartsWith("append-") - || item.Key.StartsWith("removed-")) + if (key.StartsWith("prepend-") + || key.StartsWith("append-") + || key.StartsWith("removed-")) { - ModifyContentMerge(fileContent, item.Key, item.Value); + ModifyContentMerge(fileContent, key, valueNode); } else { - fileContent[item.Key] = item.Value; + fileContent.Children[keyNode] = valueNode; } } return; } - private void ModifyContentMerge(Dictionary 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 blRemoved = false; + string realKey; + if (key.StartsWith("prepend-")) { blPrepend = true; - key = key.Replace("prepend-", ""); + realKey = key["prepend-".Length..]; } else if (key.StartsWith("append-")) { - blPrepend = false; - key = key.Replace("append-", ""); + realKey = key["append-".Length..]; } else if (key.StartsWith("removed-")) { blRemoved = true; - key = key.Replace("removed-", ""); + realKey = key["removed-".Length..]; } else { 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; } - var lstOri = (List)fileContent[key]; - var lstValue = (List)value; if (blRemoved) { - foreach (var item in lstValue) + var removePrefixes = lstValue.Children + .OfType() + .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; } if (blPrepend) { - lstValue.Reverse(); - lstValue.ForEach(item => lstOri.Insert(0, item)); + // Insert in reverse order to maintain original sequence at index 0 + for (var i = lstValue.Children.Count - 1; i >= 0; i--) + { + lstOri.Children.Insert(0, lstValue.Children[i]); + } } else { - lstValue.ForEach(lstOri.Add); + foreach (var item in lstValue.Children) + { + lstOri.Children.Add(item); + } } } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs index 4015c090..2ef891e8 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/Singbox/SingboxOutboundService.cs @@ -525,7 +525,7 @@ public partial class CoreConfigSingboxService transport.type = nameof(ETransport.http); transport.host = transportExtra.Host.IsNullOrEmpty() ? null - : Utils.String2List(transportExtra.Host); + : JsonUtils.SerializeToArray(Utils.String2List(transportExtra.Host)); transport.path = transportExtra.Path.NullIfEmpty(); if (!useragentValue.IsNullOrEmpty()) { diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs index bacbdf1d..830096bc 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayDnsService.cs @@ -17,14 +17,14 @@ public partial class CoreConfigV2rayService } // DNS routing - var dnsObj = JsonUtils.SerializeToNode(_coreConfig.dns); - if (dnsObj == null) + var dnsNode = JsonUtils.SerializeToNode(_coreConfig.dns); + if (dnsNode is not JsonObject dnsObj) { return; } dnsObj["tag"] = Global.DnsTag; - _coreConfig.dns = JsonUtils.Deserialize(JsonUtils.Serialize(dnsObj)); + _coreConfig.dns = dnsObj; _coreConfig.routing.rules.Add(new RulesItem4Ray { type = "field", @@ -34,7 +34,7 @@ public partial class CoreConfigV2rayService return; } var simpleDnsItem = context.SimpleDnsItem; - var dnsItem = _coreConfig.dns as Dns4Ray ?? new Dns4Ray(); + var dnsItem = new Dns4Ray(); var strategy4Freedom = simpleDnsItem?.Strategy4Freedom ?? Global.AsIs; //Outbound Freedom domainStrategy @@ -117,7 +117,7 @@ public partial class CoreConfigV2rayService balancerTag = finalRule.balancerTag, }); - _coreConfig.dns = dnsItem; + _coreConfig.dns = (JsonObject)JsonUtils.SerializeToNode(dnsItem); } catch (Exception ex) { @@ -317,7 +317,7 @@ public partial class CoreConfigV2rayService if (!useDirectDns) { - dnsItem.servers.AddRange(remoteDNSAddress); + dnsItem.servers.AddRange(JsonUtils.SerializeToArray(remoteDNSAddress)); } else { @@ -326,8 +326,7 @@ public partial class CoreConfigV2rayService var dnsServer = CreateDnsServer(dns, []); dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}"; dnsServer.skipFallback = false; - dnsItem.servers.Add(JsonUtils.SerializeToNode(dnsServer, - new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); + dnsItem.servers.Add(JsonUtils.SerializeToNode(dnsServer)); } } return; @@ -382,8 +381,7 @@ public partial class CoreConfigV2rayService { dnsServer.tag = $"{Global.DirectDnsTag}-{directDnsTagIndex++}"; } - var dnsServerNode = JsonUtils.SerializeToNode(dnsServer, - new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }); + var dnsServerNode = JsonUtils.SerializeToNode(dnsServer); dnsItem.servers.Add(dnsServerNode); } } @@ -396,12 +394,12 @@ public partial class CoreConfigV2rayService { return; } - dnsItem.hosts ??= new Dictionary(); + dnsItem.hosts ??= new Dictionary(); if (simpleDNSItem.AddCommonHosts == true) { dnsItem.hosts = Global.PredefinedHosts.ToDictionary( 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) { - normalHost.TryAdd(host.Key, new List { host.Value }); + normalHost.TryAdd(host.Key, JsonUtils.SerializeToArray(new List { host.Value })); } } } 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); - if (obj is null) + var node = JsonUtils.ParseJson(customDNS); + if (node is not JsonObject obj) { List servers = []; var arrDNS = customDNS.Split(','); @@ -458,8 +456,7 @@ public partial class CoreConfigV2rayService { servers.Add(str); } - obj = JsonUtils.ParseJson("{}"); - obj["servers"] = JsonUtils.SerializeToNode(servers); + obj = new JsonObject { ["servers"] = JsonUtils.SerializeToNode(servers) }; } // Append to dns settings diff --git a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs index 22ee89e5..6ae4f222 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs @@ -203,7 +203,7 @@ public partial class CoreConfigV2rayService }; 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, reserved = Utils.String2List(protocolExtra.WgReserved)?.Select(s => s.Trim()).Select(int.Parse).ToList(), mtu = protocolExtra.WgMtu > 0 ? protocolExtra.WgMtu : Global.TunMtus.First(), @@ -428,7 +428,7 @@ public partial class CoreConfigV2rayService } kcpFinalmask.udp?.Reverse(); streamSettings.kcpSettings = kcpSettings; - streamSettings.finalmask = kcpFinalmask; + streamSettings.finalmask = (JsonObject)JsonUtils.SerializeToNode(kcpFinalmask); break; //ws case nameof(ETransport.ws): @@ -489,7 +489,7 @@ public partial class CoreConfigV2rayService } if (xhttpExtra.IsNotEmpty()) { - xhttpSettings.extra = JsonUtils.ParseJson(xhttpExtra); + xhttpSettings.extra = JsonUtils.ParseJson(xhttpExtra) as JsonObject; } streamSettings.xhttpSettings = xhttpSettings; @@ -581,7 +581,7 @@ public partial class CoreConfigV2rayService auth = _node.Password, }; hy2Finalmask.udp?.Reverse(); - streamSettings.finalmask = hy2Finalmask; + streamSettings.finalmask = (JsonObject)JsonUtils.SerializeToNode(hy2Finalmask); break; case "masque": @@ -637,7 +637,7 @@ public partial class CoreConfigV2rayService pathHttp = string.Join(",".AppendQuotes(), arrPath); } request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}"); - rawSettings.header.request = JsonUtils.Deserialize(request); + rawSettings.header.request = JsonUtils.SerializeToNode(request) as JsonObject; streamSettings.rawSettings = rawSettings; } @@ -646,7 +646,7 @@ public partial class CoreConfigV2rayService if (!_node.Finalmask.IsNullOrEmpty()) { - streamSettings.finalmask = JsonUtils.ParseJson(_node.Finalmask); + streamSettings.finalmask = JsonUtils.ParseJson(_node.Finalmask) as JsonObject; } } catch (Exception ex) @@ -837,10 +837,10 @@ public partial class CoreConfigV2rayService protocol = "freedom", streamSettings = new StreamSettings4Ray { - finalmask = new Finalmask4Ray + finalmask = JsonUtils.SerializeToNode(new Finalmask4Ray { tcp = [fragmentMask], - }, + }) as JsonObject, }, }; diff --git a/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayN/ServiceLib/Services/UpdateService.cs index 3eee6c76..6b57a337 100644 --- a/v2rayN/ServiceLib/Services/UpdateService.cs +++ b/v2rayN/ServiceLib/Services/UpdateService.cs @@ -335,9 +335,13 @@ public partial class UpdateService(Config config, Func updat //Check for avalonia desktop windows version 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; } else if (Utils.IsLinux()) diff --git a/v2rayN/ServiceLib/Services/WindowsJobService.cs b/v2rayN/ServiceLib/Services/WindowsJobService.cs index c54637fb..e74abdec 100644 --- a/v2rayN/ServiceLib/Services/WindowsJobService.cs +++ b/v2rayN/ServiceLib/Services/WindowsJobService.cs @@ -24,7 +24,7 @@ public sealed class WindowsJobService : IDisposable try { - var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + var length = Marshal.SizeOf(); extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index 8cc01f02..3d5a291f 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -448,7 +448,7 @@ public partial class ProfilesViewModel : MyReactiveObject return null; } - var orderProfiles = SelectedProfiles?.OrderBy(t => t.Sort); + var orderProfiles = SelectedProfiles?.OrderBy(t => t.Sort).ToList(); if (latest) { lstSelected.AddRange(await AppManager.Instance.GetProfileItemsOrderedByIndexIds(orderProfiles.Select(sp => sp?.IndexId))); @@ -712,7 +712,7 @@ public partial class ProfilesViewModel : MyReactiveObject actionType = ESpeedActionType.Realping; } - lstSelected = JsonUtils.Deserialize>(JsonUtils.Serialize(ProfileItems?.OrderBy(t => t.Sort))); + lstSelected = JsonUtils.Deserialize>(JsonUtils.Serialize(ProfileItems?.OrderBy(t => t.Sort).ToList())); } else { diff --git a/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs b/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs index 706c9253..e9e32547 100644 --- a/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/RoutingRuleSettingViewModel.cs @@ -191,13 +191,7 @@ public partial class RoutingRuleSettingViewModel : MyReactiveObject, ICloseable } if (lst.Count > 0) { - var options = new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }; - await SetClipboardDataInteraction.HandleSafe(JsonUtils.Serialize(lst, options)); + await SetClipboardDataInteraction.HandleSafe(JsonUtils.SerializeCamelCase(lst)); } } diff --git a/v2rayN/v2rayN.Desktop/Common/QRCodeAvaloniaUtils.cs b/v2rayN/v2rayN.Desktop/Common/QRCodeAvaloniaUtils.cs index ba416e71..d0f47e38 100644 --- a/v2rayN/v2rayN.Desktop/Common/QRCodeAvaloniaUtils.cs +++ b/v2rayN/v2rayN.Desktop/Common/QRCodeAvaloniaUtils.cs @@ -69,7 +69,7 @@ public partial class QRCodeAvaloniaUtils var bmi = new BITMAPINFO { - biSize = Marshal.SizeOf(typeof(BITMAPINFO)), + biSize = Marshal.SizeOf(), biWidth = width, biHeight = -height, biPlanes = 1, diff --git a/v2rayN/v2rayN.Desktop/TrimmerRoots.xml b/v2rayN/v2rayN.Desktop/TrimmerRoots.xml new file mode 100644 index 00000000..3e8d14fb --- /dev/null +++ b/v2rayN/v2rayN.Desktop/TrimmerRoots.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/v2rayN/v2rayN.Desktop/Views/JsonEditor.axaml.cs b/v2rayN/v2rayN.Desktop/Views/JsonEditor.axaml.cs index a2a3f178..c0d8aef6 100644 --- a/v2rayN/v2rayN.Desktop/Views/JsonEditor.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/JsonEditor.axaml.cs @@ -7,8 +7,6 @@ namespace v2rayN.Desktop.Views; public partial class JsonEditor : UserControl { - private static readonly JsonSerializerOptions SIndentedOptions = new() { WriteIndented = true }; - private static readonly Lazy SHighlightingDark = new(() => BuildHighlighting(dark: true), isThreadSafe: true); @@ -88,7 +86,7 @@ public partial class JsonEditor : UserControl try { var obj = JsonUtils.ParseJson(Editor.Text); - Editor.Text = JsonUtils.Serialize(obj, SIndentedOptions); + Editor.Text = JsonUtils.Serialize(obj, indented: true, nullValue: true); } catch { diff --git a/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj b/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj index 4b631e4f..fb2274e8 100644 --- a/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj +++ b/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj @@ -55,5 +55,8 @@ Always - + + + +