From b12f1cc2f1869ef86f6740bed565b58021f08062 Mon Sep 17 00:00:00 2001 From: pas2704 Date: Sun, 1 Jun 2025 11:11:50 -0400 Subject: [PATCH] Retry source requests Handle missing sources Minor Optimizations Move thread pool improvement to debug while we fix it --- CringeLauncher/CringeLauncher.csproj | 3 +- CringeLauncher/Launcher.cs | 5 ++- .../Patches/DarkTardMissingNamespacePatch.cs | 21 ---------- CringeLauncher/Patches/ModRewriterPatch.cs | 12 +++--- .../SyntaxRewriters/MissingUsingRewriter.cs | 5 ++- CringePlugins/Loader/PluginsLifetime.cs | 17 ++++++-- CringePlugins/Resolver/PackageResolver.cs | 8 +++- CringePlugins/Ui/PluginListComponent.cs | 2 +- NuGet/Deps/DependenciesManifest.cs | 3 +- NuGet/NuGetClient.cs | 42 +++++++++++++------ NuGet/PackageSourceMapping.cs | 8 ++-- 11 files changed, 72 insertions(+), 54 deletions(-) delete mode 100644 CringeLauncher/Patches/DarkTardMissingNamespacePatch.cs diff --git a/CringeLauncher/CringeLauncher.csproj b/CringeLauncher/CringeLauncher.csproj index b0c6efe..3b03008 100644 --- a/CringeLauncher/CringeLauncher.csproj +++ b/CringeLauncher/CringeLauncher.csproj @@ -19,7 +19,8 @@ - + + diff --git a/CringeLauncher/Launcher.cs b/CringeLauncher/Launcher.cs index 01f781d..27cc6e3 100644 --- a/CringeLauncher/Launcher.cs +++ b/CringeLauncher/Launcher.cs @@ -195,8 +195,11 @@ public class Launcher : ICorePlugin private static void InitThreadPool() { +#if DEBUG ParallelTasks.Parallel.Scheduler = new ThreadPoolScheduler(); - // MySandboxGame.InitMultithreading(); +#else + MySandboxGame.InitMultithreading(); +#endif } private static void ConfigureSettings() diff --git a/CringeLauncher/Patches/DarkTardMissingNamespacePatch.cs b/CringeLauncher/Patches/DarkTardMissingNamespacePatch.cs deleted file mode 100644 index 93ad4e9..0000000 --- a/CringeLauncher/Patches/DarkTardMissingNamespacePatch.cs +++ /dev/null @@ -1,21 +0,0 @@ -using HarmonyLib; -using Sandbox.Game.World; - -namespace CringeLauncher.Patches; - -[HarmonyPatch(typeof(MyScriptManager), nameof(MyScriptManager.Init))] -public static class DarkTardMissingNamespacePatch -{ - private static void Prefix(Dictionary ___m_compatibilityChanges) - { - ___m_compatibilityChanges["using System.Runtime.Remoting.Metadata.W3cXsd2001;"] = ""; - ___m_compatibilityChanges["using System.IO.Ports;"] = ""; - ___m_compatibilityChanges["using System.Runtime.Remoting;"] = ""; - ___m_compatibilityChanges["using System.Runtime.Remoting.Messaging;"] = ""; - ___m_compatibilityChanges["using System.Numerics;"] = ""; - ___m_compatibilityChanges["using System.Runtime.Remoting.Lifetime;"] = ""; - ___m_compatibilityChanges["using System.Net.Configuration;"] = ""; - ___m_compatibilityChanges["using System.Reflection.Metadata.Ecma335;"] = ""; - ___m_compatibilityChanges["using Microsoft.VisualBasic;"] = ""; - } -} \ No newline at end of file diff --git a/CringeLauncher/Patches/ModRewriterPatch.cs b/CringeLauncher/Patches/ModRewriterPatch.cs index b69ef1e..4d251a8 100644 --- a/CringeLauncher/Patches/ModRewriterPatch.cs +++ b/CringeLauncher/Patches/ModRewriterPatch.cs @@ -1,18 +1,18 @@ using HarmonyLib; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis; -using VRage.Scripting; using CringeLauncher.SyntaxRewriters; +using VRage.Scripting.Rewriters; namespace CringeLauncher.Patches; -[HarmonyPatch(typeof(MyScriptCompiler), "InjectMod")] +[HarmonyPatch(typeof(ProtoTagRewriter), "Rewrite")] internal static class ModRewriterPatch { - public static void Prefix(ref CSharpCompilation compilation, ref SyntaxTree syntaxTree) + public static bool Prefix(CSharpCompilation compilation, SyntaxTree syntaxTree, ref SyntaxTree __result) { - var fixedSyntaxTree = MissingUsingRewriter.Rewrite(compilation, syntaxTree); - compilation = compilation.ReplaceSyntaxTree(syntaxTree, fixedSyntaxTree); - syntaxTree = fixedSyntaxTree; + __result = MissingUsingRewriter.Rewrite(compilation, syntaxTree); + + return false; } } diff --git a/CringeLauncher/SyntaxRewriters/MissingUsingRewriter.cs b/CringeLauncher/SyntaxRewriters/MissingUsingRewriter.cs index 1c71f56..bf37b47 100644 --- a/CringeLauncher/SyntaxRewriters/MissingUsingRewriter.cs +++ b/CringeLauncher/SyntaxRewriters/MissingUsingRewriter.cs @@ -2,12 +2,13 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Diagnostics; +using VRage.Scripting.Rewriters; namespace CringeLauncher.SyntaxRewriters; -internal sealed class MissingUsingRewriter : CSharpSyntaxRewriter +internal sealed class MissingUsingRewriter : ProtoTagRewriter //use existing rewriter to prevent another iteration { private readonly SemanticModel _semanticModel; - private MissingUsingRewriter(CSharpCompilation compilation, SyntaxTree tree) => _semanticModel = compilation.GetSemanticModel(tree); + private MissingUsingRewriter(CSharpCompilation compilation, SyntaxTree tree) : base(compilation, tree) => _semanticModel = compilation.GetSemanticModel(tree); public static SyntaxTree Rewrite(CSharpCompilation compilation, SyntaxTree tree) { diff --git a/CringePlugins/Loader/PluginsLifetime.cs b/CringePlugins/Loader/PluginsLifetime.cs index 5614f2a..579932d 100644 --- a/CringePlugins/Loader/PluginsLifetime.cs +++ b/CringePlugins/Loader/PluginsLifetime.cs @@ -43,7 +43,7 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage var configPath = Path.Join(_dir.FullName, "packages.json"); if (File.Exists(configPath)) await using (var stream = File.OpenRead(configPath)) - packagesConfig = JsonSerializer.Deserialize(stream, NuGetClient.SerializerOptions)!; + packagesConfig = await JsonSerializer.DeserializeAsync(stream, NuGetClient.SerializerOptions)!; if (packagesConfig == null) { @@ -114,7 +114,15 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage foreach (var package in packages) { if (builtInPackages.ContainsKey(package.Package.Id)) continue; - + + var client = await sourceMapping.GetClientAsync(package.Package.Id); + + if (client == null) + { + Log.Warn("Client not found for {Package}", package.Package.Id); + continue; + } + var dir = Path.Join(package.Directory.FullName, "lib", package.ResolvedFramework.GetShortFolderName()); var path = Path.Join(dir, $"{package.Package.Id}.deps.json"); @@ -123,6 +131,8 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage try { await using var stream = File.Create(path); + + //client should not be null for calls to this await manifestBuilder.WriteDependencyManifestAsync(stream, package.Entry, _runtimeFramework); } catch (Exception ex) @@ -132,8 +142,7 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage throw; } } - - var client = await sourceMapping.GetClientAsync(package.Package.Id); + var sourceName = packagesConfig.Sources.First(b => b.Url == client.ToString()).Name; LoadComponent(plugins, Path.Join(dir, $"{package.Package.Id}.dll"), new(package.Package.Id, package.Package.Version, sourceName)); diff --git a/CringePlugins/Resolver/PackageResolver.cs b/CringePlugins/Resolver/PackageResolver.cs index 667a356..4c1ec61 100644 --- a/CringePlugins/Resolver/PackageResolver.cs +++ b/CringePlugins/Resolver/PackageResolver.cs @@ -20,6 +20,9 @@ public class PackageResolver(NuGetFramework runtimeFramework, ImmutableArray b.Url != source.ToString())) + if (source == null || _selectedSources is not null && _selectedSources.All(b => b.Url != source.ToString())) continue; try diff --git a/NuGet/Deps/DependenciesManifest.cs b/NuGet/Deps/DependenciesManifest.cs index 844c3ca..5976446 100644 --- a/NuGet/Deps/DependenciesManifest.cs +++ b/NuGet/Deps/DependenciesManifest.cs @@ -149,7 +149,8 @@ public class DependencyManifestBuilder(DirectoryInfo cacheDirectory, PackageSour ]; } - var client = await packageSources.GetClientAsync(entry.Id); + //don't call this method if client is null + var client = await packageSources.GetClientAsync(entry.Id)!; dir.Create(); diff --git a/NuGet/NuGetClient.cs b/NuGet/NuGetClient.cs index 7d9c1aa..f21a4e1 100644 --- a/NuGet/NuGetClient.cs +++ b/NuGet/NuGetClient.cs @@ -97,25 +97,43 @@ public class NuGetClient return _client.GetFromJsonAsync(builder.Uri, SerializerOptions)!; } - public static async Task CreateFromIndexUrlAsync(string indexUrl) + public static async Task CreateFromIndexUrlAsync(string indexUrl) { var client = new HttpClient(new HttpClientHandler { - AutomaticDecompression = DecompressionMethods.All + AutomaticDecompression = DecompressionMethods.All, }); - var index = await client.GetFromJsonAsync(indexUrl, SerializerOptions); - - var (packageBaseAddress, _, _) = index!.Resources.First(b => b.Type.Id == "PackageBaseAddress"); - var (registration, _, _) = index.Resources.First(b => b.Type.Id == "RegistrationsBaseUrl"); - var (search, _, _) = index.Resources.First(b => b.Type.Id == "SearchQueryService"); + NuGetClient? ngClient = null; - if (!packageBaseAddress.EndsWith('/')) - packageBaseAddress += '/'; - if (!registration.EndsWith('/')) - registration += '/'; + const int MaxRetries = 10; - return new NuGetClient(new Uri(indexUrl), client, new Uri(packageBaseAddress), new Uri(registration), new Uri(search)); + for (var i = 0; i < MaxRetries; i++) + { + try + { + var index = await client.GetFromJsonAsync(indexUrl, SerializerOptions); + + var (packageBaseAddress, _, _) = index!.Resources.First(b => b.Type.Id == "PackageBaseAddress"); + var (registration, _, _) = index.Resources.First(b => b.Type.Id == "RegistrationsBaseUrl"); + var (search, _, _) = index.Resources.First(b => b.Type.Id == "SearchQueryService"); + + if (!packageBaseAddress.EndsWith('/')) + packageBaseAddress += '/'; + if (!registration.EndsWith('/')) + registration += '/'; + + ngClient = new NuGetClient(new Uri(indexUrl), client, new Uri(packageBaseAddress), new Uri(registration), new Uri(search)); + + break; + } + catch (HttpRequestException ex) + { + Console.WriteLine(ex.Message); + } + } + + return ngClient; } public override string ToString() => _index.ToString(); diff --git a/NuGet/PackageSourceMapping.cs b/NuGet/PackageSourceMapping.cs index 0031656..51a6d66 100644 --- a/NuGet/PackageSourceMapping.cs +++ b/NuGet/PackageSourceMapping.cs @@ -7,19 +7,19 @@ namespace NuGet; public class PackageSourceMapping(ImmutableArray sources) { - private readonly ImmutableArray<(string pattern, Task client)> _clients = [ + private readonly ImmutableArray<(string pattern, Task client)> _clients = [ ..sources.Select(b => (b.Pattern, NuGetClient.CreateFromIndexUrlAsync(b.Url))) ]; - public Task GetClientAsync(string packageId) => + public Task GetClientAsync(string packageId) => _clients.FirstOrDefault(b => Regex.IsMatch(packageId, b.pattern)).client; - public ConfiguredCancelableAsyncEnumerable.Enumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + public ConfiguredCancelableAsyncEnumerable.Enumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) { return _clients.ToAsyncEnumerable() - .SelectAwait(b => new ValueTask(b.client)) + .SelectAwait(b => new ValueTask(b.client)) .WithCancellation(cancellationToken) .GetAsyncEnumerator(); }