From b9cb71e11f2e83901cf11bf9f43501c18c4214e0 Mon Sep 17 00:00:00 2001 From: zznty <94796179+zznty@users.noreply.github.com> Date: Wed, 8 Feb 2023 15:56:50 +0700 Subject: [PATCH] introduction of nuget packages as plugins support --- Torch.API/ITorchConfig.cs | 3 +- Torch.API/Managers/IPackageManager.cs | 14 ++ Torch.API/Torch.API.csproj | 3 + Torch.API/WebAPI/Plugins/IPackageItem.cs | 11 ++ Torch.API/WebAPI/Plugins/IPackageReader.cs | 12 ++ Torch.API/WebAPI/Plugins/IPackageResolver.cs | 11 ++ Torch.API/WebAPI/Plugins/NLogLogger.cs | 87 +++++++++++ Torch.API/WebAPI/Plugins/Package.cs | 10 ++ Torch.API/WebAPI/Plugins/PackageDependency.cs | 9 ++ .../WebAPI/Plugins/PackageDependencyKind.cs | 8 + Torch.API/WebAPI/Plugins/PackageReader.cs | 91 +++++++++++ Torch.API/WebAPI/Plugins/PackageResolver.cs | 104 +++++++++++++ Torch.API/WebAPI/Plugins/PackageSource.cs | 8 + Torch.API/WebAPI/Plugins/PackageSourceType.cs | 8 + Torch.API/packages.lock.json | 139 +++++++++++++++++ Torch.Server/TorchConfig.cs | 3 + Torch.Server/packages.lock.json | 139 ++++++++++++++++- Torch/Plugins/PluginManager.cs | 4 +- Torch/TorchBase.cs | 10 +- Torch/packages.lock.json | 141 +++++++++++++++++- 20 files changed, 805 insertions(+), 10 deletions(-) create mode 100644 Torch.API/Managers/IPackageManager.cs create mode 100644 Torch.API/WebAPI/Plugins/IPackageItem.cs create mode 100644 Torch.API/WebAPI/Plugins/IPackageReader.cs create mode 100644 Torch.API/WebAPI/Plugins/IPackageResolver.cs create mode 100644 Torch.API/WebAPI/Plugins/NLogLogger.cs create mode 100644 Torch.API/WebAPI/Plugins/Package.cs create mode 100644 Torch.API/WebAPI/Plugins/PackageDependency.cs create mode 100644 Torch.API/WebAPI/Plugins/PackageDependencyKind.cs create mode 100644 Torch.API/WebAPI/Plugins/PackageReader.cs create mode 100644 Torch.API/WebAPI/Plugins/PackageResolver.cs create mode 100644 Torch.API/WebAPI/Plugins/PackageSource.cs create mode 100644 Torch.API/WebAPI/Plugins/PackageSourceType.cs diff --git a/Torch.API/ITorchConfig.cs b/Torch.API/ITorchConfig.cs index 8559fe0..5d03cfe 100644 --- a/Torch.API/ITorchConfig.cs +++ b/Torch.API/ITorchConfig.cs @@ -33,7 +33,8 @@ namespace Torch bool EntityManagerEnabled { get; set; } string LoginToken { get; set; } UpdateSource UpdateSource { get; set; } - + List Packages { get; set; } + void Save(string path = null); } diff --git a/Torch.API/Managers/IPackageManager.cs b/Torch.API/Managers/IPackageManager.cs new file mode 100644 index 0000000..8338e4b --- /dev/null +++ b/Torch.API/Managers/IPackageManager.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.Loader; +using Torch.API.WebAPI.Plugins; + +namespace Torch.API.Managers; + +public interface IPackageManager : IManager +{ + IReadOnlySet Packages { get; } + + bool TryGetPackageAssemblies(Package package, [MaybeNullWhen(false)] out Assembly[] assemblies); +} \ No newline at end of file diff --git a/Torch.API/Torch.API.csproj b/Torch.API/Torch.API.csproj index 7490b04..7c8f151 100644 --- a/Torch.API/Torch.API.csproj +++ b/Torch.API/Torch.API.csproj @@ -18,10 +18,13 @@ + + all compile + \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/IPackageItem.cs b/Torch.API/WebAPI/Plugins/IPackageItem.cs new file mode 100644 index 0000000..4e32808 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/IPackageItem.cs @@ -0,0 +1,11 @@ +#nullable enable +using System.IO; +using System.Threading.Tasks; + +namespace Torch.API.WebAPI.Plugins; + +public interface IPackageItem +{ + Task OpenFileAsync(); + public string FileName { get; } +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/IPackageReader.cs b/Torch.API/WebAPI/Plugins/IPackageReader.cs new file mode 100644 index 0000000..494a8c1 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/IPackageReader.cs @@ -0,0 +1,12 @@ +#nullable enable +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace Torch.API.WebAPI.Plugins; + +public interface IPackageReader +{ + Task<(IEnumerable Root, IReadOnlyDictionary> Dependencies)> GetItemsAsync(); +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/IPackageResolver.cs b/Torch.API/WebAPI/Plugins/IPackageResolver.cs new file mode 100644 index 0000000..2e1177b --- /dev/null +++ b/Torch.API/WebAPI/Plugins/IPackageResolver.cs @@ -0,0 +1,11 @@ +#nullable enable +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Torch.API.WebAPI.Plugins; + +public interface IPackageResolver +{ + Task> ResolvePackagesAsync(IReadOnlyDictionary packages); + Task GetPackageAsync(Package package); +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/NLogLogger.cs b/Torch.API/WebAPI/Plugins/NLogLogger.cs new file mode 100644 index 0000000..f3593fd --- /dev/null +++ b/Torch.API/WebAPI/Plugins/NLogLogger.cs @@ -0,0 +1,87 @@ +#nullable enable +using System; +using System.Threading.Tasks; +using NuGet.Common; + +namespace Torch.API.WebAPI.Plugins; + +internal class NLogLogger : ILogger +{ + private readonly NLog.ILogger _logger; + + public NLogLogger(NLog.ILogger logger) + { + _logger = logger; + } + + public void LogDebug(string data) + { + _logger.Debug(data); + } + + public void LogVerbose(string data) + { + _logger.Trace(data); + } + + public void LogInformation(string data) + { + _logger.Info(data); + } + + public void LogMinimal(string data) + { + _logger.Debug(data); + } + + public void LogWarning(string data) + { + _logger.Warn(data); + } + + public void LogError(string data) + { + _logger.Error(data); + } + + public void LogInformationSummary(string data) + { + _logger.Info(data); + } + + public void Log(LogLevel level, string data) + { + _logger.Log(ToNLogLevel(level), data); + } + + private static NLog.LogLevel ToNLogLevel(LogLevel level) + { + return level switch + { + LogLevel.Debug => NLog.LogLevel.Debug, + LogLevel.Verbose => NLog.LogLevel.Trace, + LogLevel.Information => NLog.LogLevel.Info, + LogLevel.Minimal => NLog.LogLevel.Debug, + LogLevel.Warning => NLog.LogLevel.Warn, + LogLevel.Error => NLog.LogLevel.Error, + _ => throw new ArgumentOutOfRangeException(nameof(level), level, null) + }; + } + + public Task LogAsync(LogLevel level, string data) + { + Log(level, data); + return Task.CompletedTask; + } + + public void Log(ILogMessage message) + { + _logger.Log(ToNLogLevel(message.Level), message.FormatWithCode); + } + + public Task LogAsync(ILogMessage message) + { + Log(message); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/Package.cs b/Torch.API/WebAPI/Plugins/Package.cs new file mode 100644 index 0000000..1e09368 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/Package.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using NuGet.DependencyResolver; +using SemanticVersioning; + +namespace Torch.API.WebAPI.Plugins; + +public record Package(string Name, Version Version, IReadOnlySet Dependencies) +{ + internal GraphItem Graph { get; init; } +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/PackageDependency.cs b/Torch.API/WebAPI/Plugins/PackageDependency.cs new file mode 100644 index 0000000..8ef1ca9 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/PackageDependency.cs @@ -0,0 +1,9 @@ +using NuGet.DependencyResolver; +using SemanticVersioning; + +namespace Torch.API.WebAPI.Plugins; + +public record PackageDependency(string Name, Version Version, PackageDependencyKind Kind) +{ + internal RemoteMatch Match { get; init; } +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/PackageDependencyKind.cs b/Torch.API/WebAPI/Plugins/PackageDependencyKind.cs new file mode 100644 index 0000000..1e93cc7 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/PackageDependencyKind.cs @@ -0,0 +1,8 @@ +namespace Torch.API.WebAPI.Plugins; + +public enum PackageDependencyKind +{ + None, + Transitive, + Direct +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/PackageReader.cs b/Torch.API/WebAPI/Plugins/PackageReader.cs new file mode 100644 index 0000000..c5a05d4 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/PackageReader.cs @@ -0,0 +1,91 @@ +#nullable enable +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using NuGet.Common; +using NuGet.DependencyResolver; +using NuGet.Frameworks; +using NuGet.Packaging; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; + +namespace Torch.API.WebAPI.Plugins; + +public class PackageReader : IPackageReader +{ + private readonly Package _package; + private readonly SourceCacheContext _cacheContext; + private readonly ILogger _logger; + private readonly NuGetFramework _framework; + private readonly IFrameworkCompatibilityProvider _compatibilityProvider; + private readonly DirectoryInfo _packagesDirectory; + + public PackageReader(Package package, SourceCacheContext cacheContext, ILogger logger, NuGetFramework framework, + IFrameworkCompatibilityProvider compatibilityProvider, DirectoryInfo packagesDirectory) + { + _package = package; + _cacheContext = cacheContext; + _logger = logger; + _framework = framework; + _compatibilityProvider = compatibilityProvider; + _packagesDirectory = packagesDirectory; + } + + public async Task<(IEnumerable Root, IReadOnlyDictionary> + Dependencies)> + GetItemsAsync() + { + async Task> GetPackageItemsAsync(string id, NuGetVersion version, + IRemoteDependencyProvider provider) + { + var downloader = + await provider.GetPackageDownloaderAsync(new(id, version), _cacheContext, _logger, + CancellationToken.None); + + await downloader.CopyNupkgFileToAsync(Path.Combine(_packagesDirectory.FullName, $"{id}.{version}.nupkg"), + CancellationToken.None); + + var frameworks = await downloader.ContentReader.GetReferenceItemsAsync(CancellationToken.None); + var items = frameworks.Where(b => _compatibilityProvider.IsCompatible(_framework, b.TargetFramework)) + .MaxBy(b => b.TargetFramework.Version)?.Items; + + return items?.Select(b => new PackageItem(b, downloader)) ?? ImmutableArray.Empty; + } + + var rootIdentity = _package.Graph.Key; + return (await GetPackageItemsAsync(rootIdentity.Name, rootIdentity.Version, _package.Graph.Data.Match.Provider), + await _package.Dependencies.ToAsyncEnumerable().SelectManyAwait(async b => + (await GetPackageItemsAsync( + b.Match.Library.Name, + b.Match.Library.Version, + b.Match.Provider)) + .ToAsyncEnumerable() + .Select(c => (b, c))) + .GroupBy(b => b.b, b => b.c) + .ToDictionaryAwaitAsync, PackageDependency, + IEnumerable>(b => ValueTask.FromResult(b.Key), + async b => await b.ToArrayAsync())); + } +} + +file class PackageItem : IPackageItem +{ + private readonly string _path; + private readonly IPackageDownloader _downloader; + + public string FileName => Path.GetFileName(_path); + + public PackageItem(string path, IPackageDownloader downloader) + { + _path = path; + _downloader = downloader; + } + + public Task OpenFileAsync() + { + return _downloader.CoreReader.GetStreamAsync(_path, CancellationToken.None); + } +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/PackageResolver.cs b/Torch.API/WebAPI/Plugins/PackageResolver.cs new file mode 100644 index 0000000..a3c7442 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/PackageResolver.cs @@ -0,0 +1,104 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using NLog; +using NuGet.Commands; +using NuGet.Configuration; +using NuGet.DependencyResolver; +using NuGet.Frameworks; +using NuGet.LibraryModel; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; +using Version = SemanticVersioning.Version; + +namespace Torch.API.WebAPI.Plugins; + +public class PackageResolver : IPackageResolver +{ + private static readonly ILogger Log = LogManager.GetCurrentClassLogger(); + + private readonly NuGetFramework _framework = NuGetFramework.Parse("net7.0-windows7.0"); + private readonly NLogLogger _logger = new(Log); + private readonly SourceCacheContext _sourceCacheContext = new(); + private readonly RemoteWalkContext _remoteWalkContext; + private readonly DirectoryInfo _packagesDirectory; + private readonly IFrameworkCompatibilityProvider _compatibilityProvider = DefaultCompatibilityProvider.Instance; + + public PackageResolver(IEnumerable sources, DirectoryInfo packagesDirectory) + { + _packagesDirectory = packagesDirectory; + IReadOnlySet packageSources = sources.Where(b => b.Type is PackageSourceType.NuGet).ToImmutableHashSet(); + + var mapping = new PackageSourceMapping(packageSources.ToDictionary(b => b.Name, b => b.Patterns)); + _remoteWalkContext = new RemoteWalkContext(_sourceCacheContext, mapping, _logger); + + foreach (var (name, url, _, _) in packageSources) + { + var packageSource = new NuGet.Configuration.PackageSource(url, name); + var sourceRepository = new SourceRepository(packageSource, new INuGetResourceProvider[] + { + new DownloadResourceV3Provider(), + new DependencyInfoResourceV3Provider(), + new ServiceIndexResourceV3Provider(), + new RemoteV3FindPackageByIdResourceProvider(), + new V3FeedListResourceProvider(), + new HttpSourceResourceProvider(), + new RegistrationResourceV3Provider(), + new HttpHandlerResourceV3Provider() + }.Select(b => new Lazy(b)), FeedType.HttpV3); + + _remoteWalkContext.RemoteLibraryProviders.Add( + new SourceRepositoryDependencyProvider(sourceRepository, _logger, _sourceCacheContext, true, false)); + } + } + + public async Task> ResolvePackagesAsync( + IReadOnlyDictionary packages) + { + Log.Info("Restoring {0} packages", packages.Count); + + var graphs = await Task.WhenAll(packages.Select(b => + { + var (key, versionRange) = b; + var libraryRange = new LibraryRange(key, VersionRange.Parse(versionRange), LibraryDependencyTarget.All); + return ResolverUtility.FindLibraryEntryAsync(libraryRange, _framework, "win-x64", + _remoteWalkContext, CancellationToken.None); + })); + + return await graphs.ToAsyncEnumerable().SelectAwait(async graph => + { + return new Package(graph.Key.Name, Version.Parse(graph.Key.Version.ToFullString()), + await graph.Data.Dependencies + .ToAsyncEnumerable() + .SelectAwait(async b => + { + var match = await ResolverUtility.FindLibraryByVersionAsync( + b.LibraryRange, _framework, _remoteWalkContext.RemoteLibraryProviders, + _sourceCacheContext, _logger, CancellationToken.None); + + return new PackageDependency( + b.Name, Version.Parse(match.Library.Version.ToFullString()), + (PackageDependencyKind)b.ReferenceType) + { + Match = match + }; + }) + .ToHashSetAsync()) + { + Graph = graph + }; + }).ToArrayAsync(); + } + + public Task GetPackageAsync(Package package) + { + var reader = new PackageReader(package, _sourceCacheContext, _logger, _framework, _compatibilityProvider, _packagesDirectory); + return Task.FromResult(reader); + } +} \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/PackageSource.cs b/Torch.API/WebAPI/Plugins/PackageSource.cs new file mode 100644 index 0000000..2ad9909 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/PackageSource.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Torch.API.WebAPI.Plugins; + +#nullable enable +public record PackageSource +#nullable restore + (string Name, string Url, IReadOnlyList Patterns, PackageSourceType Type); \ No newline at end of file diff --git a/Torch.API/WebAPI/Plugins/PackageSourceType.cs b/Torch.API/WebAPI/Plugins/PackageSourceType.cs new file mode 100644 index 0000000..bd09e80 --- /dev/null +++ b/Torch.API/WebAPI/Plugins/PackageSourceType.cs @@ -0,0 +1,8 @@ +#nullable enable +namespace Torch.API.WebAPI.Plugins; + +public enum PackageSourceType +{ + NuGet, + LegacyTorch +} \ No newline at end of file diff --git a/Torch.API/packages.lock.json b/Torch.API/packages.lock.json index 034cd04..77dde96 100644 --- a/Torch.API/packages.lock.json +++ b/Torch.API/packages.lock.json @@ -14,6 +14,27 @@ "resolved": "5.1.0", "contentHash": "oW7ekrkRG9okpDMUcEglunWj8Qf2RY8qkgl+/chJoavzg3dbT13y32t19R54FKkmq80fKzw4ZekZkCrRGanKgQ==" }, + "NuGet.Commands": { + "type": "Direct", + "requested": "[6.4.0, )", + "resolved": "6.4.0", + "contentHash": "j3ma45boGZADsHpJcu3Y2yq+n2luicC6ezd61TXTTzbOzA452oAPaSsFGUB1stIsuP/DVoqkTzjHXjaCHuJKPQ==", + "dependencies": { + "NuGet.Credentials": "6.4.0", + "NuGet.ProjectModel": "6.4.0" + } + }, + "NuGet.DependencyResolver.Core": { + "type": "Direct", + "requested": "[6.4.0, )", + "resolved": "6.4.0", + "contentHash": "AKomZEKuhQlshujuiHbKvwl2cZNGq3SHsXFbpjCfCjMFMLwwA8saJGQQZp1lzsqQWcQWa6hLOcPtm7T3rd0SVg==", + "dependencies": { + "NuGet.Configuration": "6.4.0", + "NuGet.LibraryModel": "6.4.0", + "NuGet.Protocol": "6.4.0" + } + }, "SemanticVersioning": { "type": "Direct", "requested": "[2.0.2, )", @@ -29,10 +50,128 @@ "protobuf-net": "1.0.0" } }, + "System.Linq.Async": { + "type": "Direct", + "requested": "[6.0.1, )", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "NuGet.Common": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "srECugLk+LB1bXelDCDhHoi6do/EYTXzuntKhjHraS4roVB3NfWohEdCSiAPdpSV9M40Q6jo6MV2Srml9e+jHQ==", + "dependencies": { + "NuGet.Frameworks": "6.4.0" + } + }, + "NuGet.Configuration": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "vPjauG9AoacEjiZWGIs+d11FCRVmseqAw78FIApfLvZrYMEbbwc9vc0LdC3PpoW5FxYkktyZSiiXVKXGLu+gXw==", + "dependencies": { + "NuGet.Common": "6.4.0", + "System.Security.Cryptography.ProtectedData": "4.4.0" + } + }, + "NuGet.Credentials": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "tebsxclknVz3D4FrvE2MzVcsOyf6PffjGNQ77X9Yvbj9x5YpVWfumVPetqETcdsNEgiN0bBzfMre33lhrY7Itw==", + "dependencies": { + "NuGet.Protocol": "6.4.0" + } + }, + "NuGet.Frameworks": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "qcufbjJIDtyY/Hah7JJfcRVpRYM3scgPqYBnukjO9kfADCFGr2azvVBozuwzljA6w/cR3w8bXLq6vW5xGrsmHw==" + }, + "NuGet.LibraryModel": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "K6ROQpWr34Aje81G0HfipiznLTB8vD4BO8sF6FEwx1KjJVdFkSmGZPmAhc6L1vZPs8TKY5BqoH72zG13zVzW2w==", + "dependencies": { + "NuGet.Common": "6.4.0", + "NuGet.Versioning": "6.4.0" + } + }, + "NuGet.Packaging": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "aR10aYqcUMGC2mwMGH5rls/MGaz3EVH8DKTTHQ/EC91hXNtrCTTAQonaRR+v1EItcoxtQeZ/WQOorv4z270Tgg==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "NuGet.Configuration": "6.4.0", + "NuGet.Versioning": "6.4.0", + "System.Security.Cryptography.Cng": "5.0.0", + "System.Security.Cryptography.Pkcs": "5.0.0" + } + }, + "NuGet.ProjectModel": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "eW9Q7vPk8cpXDd5b+vtIPkl8dSDCPkPJPrjXPTfZGxhstldnhJrj1XPaonsDZLQ24YY7LrYCzC0BiHh3iO5zUA==", + "dependencies": { + "NuGet.DependencyResolver.Core": "6.4.0" + } + }, + "NuGet.Protocol": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "KIPjsWP0P3EMsDsXaa6YBCTvYKur/zI0luS1kO5G37ci8mHs2kJFsuG5qaMhGvgyHASu54sxlic1n1oza2Pcbw==", + "dependencies": { + "NuGet.Packaging": "6.4.0" + } + }, + "NuGet.Versioning": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "YE8p3TpX4jIw+Gb24maE8YRDoqWA4imLmCbdOj5IvslLrZJXQ8akeFOGOplxICNVevON1g1SFYT2+cq4yy0nQQ==" + }, "protobuf-net": { "type": "Transitive", "resolved": "1.0.0", "contentHash": "kTGOK0E87473sOImOjgZOnz3kTC2aMLffoRWQLYNuBLJnwNNmjanF9IkevZ9Q7yYLeABQfcF3BpeepuMntMVNw==" + }, + "System.Formats.Asn1": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "MTvUIktmemNB+El0Fgw9egyqT9AYSIk6DTJeoDSpc3GIHxHCMo8COqkWT1mptX5tZ1SlQ6HJZ0OsSvMth1c12w==" + }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "jIMXsKn94T9JY7PvPq/tMfqa6GAaHpElRDpmG+SuL+D3+sTw2M8VhnibKnN8Tq+4JqbPJ/f+BwtLeDMEnzAvRg==", + "dependencies": { + "System.Formats.Asn1": "5.0.0" + } + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "9TPLGjBCGKmNvG8pjwPeuYy0SMVmGZRwlTZvyPHDbYv/DRkoeumJdfumaaDNQzVGMEmbWtg07zUpSW9q70IlDQ==", + "dependencies": { + "System.Formats.Asn1": "5.0.0", + "System.Security.Cryptography.Cng": "5.0.0" + } + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==" } } } diff --git a/Torch.Server/TorchConfig.cs b/Torch.Server/TorchConfig.cs index e40dfea..8d0571b 100644 --- a/Torch.Server/TorchConfig.cs +++ b/Torch.Server/TorchConfig.cs @@ -119,6 +119,9 @@ public class TorchConfig : ViewModel, ITorchConfig SourceType = UpdateSourceType.Github }; + [Display(Name = "Packages", Description = "Packages to install and use.", GroupName = "Server")] + public List Packages { get; set; } = new(); + // for backward compatibility public void Save(string path = null) => Initializer.Instance?.ConfigPersistent?.Save(path); } \ No newline at end of file diff --git a/Torch.Server/packages.lock.json b/Torch.Server/packages.lock.json index cfb26c6..2703515 100644 --- a/Torch.Server/packages.lock.json +++ b/Torch.Server/packages.lock.json @@ -182,8 +182,8 @@ }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "1Am6l4Vpn3/K32daEqZI+FFr96OlZkgwK2LcT3pZ2zWubR5zTPW3/FkO1Rat9kb7oQOa4rxgl9LJHc5tspCWfg==" + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, "Microsoft.CodeAnalysis.Analyzers": { "type": "Transitive", @@ -364,6 +364,102 @@ "MonoModReorg.ILHelpers": "22.11.21-prerelease.2" } }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "NuGet.Commands": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "j3ma45boGZADsHpJcu3Y2yq+n2luicC6ezd61TXTTzbOzA452oAPaSsFGUB1stIsuP/DVoqkTzjHXjaCHuJKPQ==", + "dependencies": { + "NuGet.Credentials": "6.4.0", + "NuGet.ProjectModel": "6.4.0" + } + }, + "NuGet.Common": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "srECugLk+LB1bXelDCDhHoi6do/EYTXzuntKhjHraS4roVB3NfWohEdCSiAPdpSV9M40Q6jo6MV2Srml9e+jHQ==", + "dependencies": { + "NuGet.Frameworks": "6.4.0" + } + }, + "NuGet.Configuration": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "vPjauG9AoacEjiZWGIs+d11FCRVmseqAw78FIApfLvZrYMEbbwc9vc0LdC3PpoW5FxYkktyZSiiXVKXGLu+gXw==", + "dependencies": { + "NuGet.Common": "6.4.0", + "System.Security.Cryptography.ProtectedData": "4.4.0" + } + }, + "NuGet.Credentials": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "tebsxclknVz3D4FrvE2MzVcsOyf6PffjGNQ77X9Yvbj9x5YpVWfumVPetqETcdsNEgiN0bBzfMre33lhrY7Itw==", + "dependencies": { + "NuGet.Protocol": "6.4.0" + } + }, + "NuGet.DependencyResolver.Core": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "AKomZEKuhQlshujuiHbKvwl2cZNGq3SHsXFbpjCfCjMFMLwwA8saJGQQZp1lzsqQWcQWa6hLOcPtm7T3rd0SVg==", + "dependencies": { + "NuGet.Configuration": "6.4.0", + "NuGet.LibraryModel": "6.4.0", + "NuGet.Protocol": "6.4.0" + } + }, + "NuGet.Frameworks": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "qcufbjJIDtyY/Hah7JJfcRVpRYM3scgPqYBnukjO9kfADCFGr2azvVBozuwzljA6w/cR3w8bXLq6vW5xGrsmHw==" + }, + "NuGet.LibraryModel": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "K6ROQpWr34Aje81G0HfipiznLTB8vD4BO8sF6FEwx1KjJVdFkSmGZPmAhc6L1vZPs8TKY5BqoH72zG13zVzW2w==", + "dependencies": { + "NuGet.Common": "6.4.0", + "NuGet.Versioning": "6.4.0" + } + }, + "NuGet.Packaging": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "aR10aYqcUMGC2mwMGH5rls/MGaz3EVH8DKTTHQ/EC91hXNtrCTTAQonaRR+v1EItcoxtQeZ/WQOorv4z270Tgg==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "NuGet.Configuration": "6.4.0", + "NuGet.Versioning": "6.4.0", + "System.Security.Cryptography.Cng": "5.0.0", + "System.Security.Cryptography.Pkcs": "5.0.0" + } + }, + "NuGet.ProjectModel": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "eW9Q7vPk8cpXDd5b+vtIPkl8dSDCPkPJPrjXPTfZGxhstldnhJrj1XPaonsDZLQ24YY7LrYCzC0BiHh3iO5zUA==", + "dependencies": { + "NuGet.DependencyResolver.Core": "6.4.0" + } + }, + "NuGet.Protocol": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "KIPjsWP0P3EMsDsXaa6YBCTvYKur/zI0luS1kO5G37ci8mHs2kJFsuG5qaMhGvgyHASu54sxlic1n1oza2Pcbw==", + "dependencies": { + "NuGet.Packaging": "6.4.0" + } + }, + "NuGet.Versioning": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "YE8p3TpX4jIw+Gb24maE8YRDoqWA4imLmCbdOj5IvslLrZJXQ8akeFOGOplxICNVevON1g1SFYT2+cq4yy0nQQ==" + }, "protobuf-net": { "type": "Transitive", "resolved": "3.1.26", @@ -408,6 +504,14 @@ "resolved": "7.0.0", "contentHash": "+nfpV0afLmvJW8+pLlHxRjz3oZJw4fkyU9MMEaMhCsHi/SN9bGF9q79ROubDiwTiCHezmK0uCWkPP7tGFP/4yg==" }, + "System.Linq.Async": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "System.Memory": { "type": "Transitive", "resolved": "4.5.5", @@ -433,6 +537,14 @@ "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "jIMXsKn94T9JY7PvPq/tMfqa6GAaHpElRDpmG+SuL+D3+sTw2M8VhnibKnN8Tq+4JqbPJ/f+BwtLeDMEnzAvRg==", + "dependencies": { + "System.Formats.Asn1": "5.0.0" + } + }, "System.Security.Cryptography.Pkcs": { "type": "Transitive", "resolved": "7.0.0", @@ -441,6 +553,11 @@ "System.Formats.Asn1": "7.0.0" } }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==" + }, "System.Security.Cryptography.Xml": { "type": "Transitive", "resolved": "7.0.0", @@ -497,7 +614,10 @@ "dependencies": { "JorgeSerrano.Json.JsonSnakeCaseNamingPolicy": "[0.9.0, )", "NLog": "[5.1.0, )", - "SemanticVersioning": "[2.0.2, )" + "NuGet.Commands": "[6.4.0, )", + "NuGet.DependencyResolver.Core": "[6.4.0, )", + "SemanticVersioning": "[2.0.2, )", + "System.Linq.Async": "[6.0.1, )" } } }, @@ -517,6 +637,14 @@ "System.CodeDom": "7.0.0" } }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "jIMXsKn94T9JY7PvPq/tMfqa6GAaHpElRDpmG+SuL+D3+sTw2M8VhnibKnN8Tq+4JqbPJ/f+BwtLeDMEnzAvRg==", + "dependencies": { + "System.Formats.Asn1": "5.0.0" + } + }, "System.Security.Cryptography.Pkcs": { "type": "Transitive", "resolved": "7.0.0", @@ -525,6 +653,11 @@ "System.Formats.Asn1": "7.0.0" } }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==" + }, "System.Text.Encoding.CodePages": { "type": "Transitive", "resolved": "6.0.0", diff --git a/Torch/Plugins/PluginManager.cs b/Torch/Plugins/PluginManager.cs index db66aaa..812c05b 100644 --- a/Torch/Plugins/PluginManager.cs +++ b/Torch/Plugins/PluginManager.cs @@ -431,8 +431,8 @@ namespace Torch.Managers return a.Name == b.Name && b.Version >= a.Version; } - - private void InstantiatePlugin(PluginManifest manifest, IEnumerable assemblies) + + internal void InstantiatePlugin(PluginManifest manifest, IEnumerable assemblies) { Type pluginType = null; bool mult = false; diff --git a/Torch/TorchBase.cs b/Torch/TorchBase.cs index b6f1661..71ff3f9 100644 --- a/Torch/TorchBase.cs +++ b/Torch/TorchBase.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; @@ -11,7 +10,6 @@ using Sandbox; using Sandbox.Game; using Sandbox.Game.Multiplayer; using Sandbox.Game.Screens.Helpers; -using SpaceEngineers.Game; using Torch.API; using Torch.API.Managers; using Torch.API.ModAPI; @@ -21,10 +19,10 @@ using Torch.Event; using Torch.Managers; using Torch.Managers.ChatManager; using Torch.Managers.PatchManager; +using Torch.Packages; using Torch.Patches; using Torch.Utils; using Torch.Session; -using VRage.Platform.Windows; using VRage.Plugins; using VRage.Utils; @@ -127,6 +125,7 @@ namespace Torch Managers.AddManager(new EventManager(this)); #pragma warning disable CS0618 Managers.AddManager(Plugins); + Managers.AddManager(new PackageManager(this, (PluginManager)Plugins)); #pragma warning restore CS0618 Managers.AddManager(new ScriptCompilationManager(this)); TorchAPI.Instance = this; @@ -286,6 +285,11 @@ namespace Torch Log.Info($"Executing directory: {AppDomain.CurrentDomain.BaseDirectory}"); Managers.GetManager().LoadPlugins(); + + var semaphore = new SemaphoreSlim(0, 1); + Managers.GetManager().LoadAsync(semaphore); + semaphore.Wait(); + Game = new VRageGame(this, TweakGameSettings, SteamAppName, SteamAppId, InstancePath, RunArgs); if (!Game.WaitFor(VRageGame.GameState.Stopped)) Log.Warn("Failed to wait for game to be initialized"); diff --git a/Torch/packages.lock.json b/Torch/packages.lock.json index 0280b31..f63e7c0 100644 --- a/Torch/packages.lock.json +++ b/Torch/packages.lock.json @@ -137,6 +137,11 @@ "resolved": "0.9.0", "contentHash": "xCqODS+wzpUXNtg4bMMvXG5PLbP0iTwRzRn2R+zWHKm83E6tbV2bCagawXp1EnZeNpd5OXpMxehulZWns8efzQ==" }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, "Microsoft.CodeAnalysis.Analyzers": { "type": "Transitive", "resolved": "3.3.3", @@ -186,6 +191,102 @@ "MonoModReorg.ILHelpers": "22.11.21-prerelease.2" } }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "NuGet.Commands": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "j3ma45boGZADsHpJcu3Y2yq+n2luicC6ezd61TXTTzbOzA452oAPaSsFGUB1stIsuP/DVoqkTzjHXjaCHuJKPQ==", + "dependencies": { + "NuGet.Credentials": "6.4.0", + "NuGet.ProjectModel": "6.4.0" + } + }, + "NuGet.Common": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "srECugLk+LB1bXelDCDhHoi6do/EYTXzuntKhjHraS4roVB3NfWohEdCSiAPdpSV9M40Q6jo6MV2Srml9e+jHQ==", + "dependencies": { + "NuGet.Frameworks": "6.4.0" + } + }, + "NuGet.Configuration": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "vPjauG9AoacEjiZWGIs+d11FCRVmseqAw78FIApfLvZrYMEbbwc9vc0LdC3PpoW5FxYkktyZSiiXVKXGLu+gXw==", + "dependencies": { + "NuGet.Common": "6.4.0", + "System.Security.Cryptography.ProtectedData": "4.4.0" + } + }, + "NuGet.Credentials": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "tebsxclknVz3D4FrvE2MzVcsOyf6PffjGNQ77X9Yvbj9x5YpVWfumVPetqETcdsNEgiN0bBzfMre33lhrY7Itw==", + "dependencies": { + "NuGet.Protocol": "6.4.0" + } + }, + "NuGet.DependencyResolver.Core": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "AKomZEKuhQlshujuiHbKvwl2cZNGq3SHsXFbpjCfCjMFMLwwA8saJGQQZp1lzsqQWcQWa6hLOcPtm7T3rd0SVg==", + "dependencies": { + "NuGet.Configuration": "6.4.0", + "NuGet.LibraryModel": "6.4.0", + "NuGet.Protocol": "6.4.0" + } + }, + "NuGet.Frameworks": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "qcufbjJIDtyY/Hah7JJfcRVpRYM3scgPqYBnukjO9kfADCFGr2azvVBozuwzljA6w/cR3w8bXLq6vW5xGrsmHw==" + }, + "NuGet.LibraryModel": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "K6ROQpWr34Aje81G0HfipiznLTB8vD4BO8sF6FEwx1KjJVdFkSmGZPmAhc6L1vZPs8TKY5BqoH72zG13zVzW2w==", + "dependencies": { + "NuGet.Common": "6.4.0", + "NuGet.Versioning": "6.4.0" + } + }, + "NuGet.Packaging": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "aR10aYqcUMGC2mwMGH5rls/MGaz3EVH8DKTTHQ/EC91hXNtrCTTAQonaRR+v1EItcoxtQeZ/WQOorv4z270Tgg==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "NuGet.Configuration": "6.4.0", + "NuGet.Versioning": "6.4.0", + "System.Security.Cryptography.Cng": "5.0.0", + "System.Security.Cryptography.Pkcs": "5.0.0" + } + }, + "NuGet.ProjectModel": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "eW9Q7vPk8cpXDd5b+vtIPkl8dSDCPkPJPrjXPTfZGxhstldnhJrj1XPaonsDZLQ24YY7LrYCzC0BiHh3iO5zUA==", + "dependencies": { + "NuGet.DependencyResolver.Core": "6.4.0" + } + }, + "NuGet.Protocol": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "KIPjsWP0P3EMsDsXaa6YBCTvYKur/zI0luS1kO5G37ci8mHs2kJFsuG5qaMhGvgyHASu54sxlic1n1oza2Pcbw==", + "dependencies": { + "NuGet.Packaging": "6.4.0" + } + }, + "NuGet.Versioning": { + "type": "Transitive", + "resolved": "6.4.0", + "contentHash": "YE8p3TpX4jIw+Gb24maE8YRDoqWA4imLmCbdOj5IvslLrZJXQ8akeFOGOplxICNVevON1g1SFYT2+cq4yy0nQQ==" + }, "protobuf-net.Core": { "type": "Transitive", "resolved": "3.1.26", @@ -212,6 +313,19 @@ "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, + "System.Formats.Asn1": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "MTvUIktmemNB+El0Fgw9egyqT9AYSIk6DTJeoDSpc3GIHxHCMo8COqkWT1mptX5tZ1SlQ6HJZ0OsSvMth1c12w==" + }, + "System.Linq.Async": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, "System.Memory": { "type": "Transitive", "resolved": "4.5.5", @@ -237,6 +351,28 @@ "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "jIMXsKn94T9JY7PvPq/tMfqa6GAaHpElRDpmG+SuL+D3+sTw2M8VhnibKnN8Tq+4JqbPJ/f+BwtLeDMEnzAvRg==", + "dependencies": { + "System.Formats.Asn1": "5.0.0" + } + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "9TPLGjBCGKmNvG8pjwPeuYy0SMVmGZRwlTZvyPHDbYv/DRkoeumJdfumaaDNQzVGMEmbWtg07zUpSW9q70IlDQ==", + "dependencies": { + "System.Formats.Asn1": "5.0.0", + "System.Security.Cryptography.Cng": "5.0.0" + } + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==" + }, "System.Text.Encoding.CodePages": { "type": "Transitive", "resolved": "6.0.0", @@ -260,7 +396,10 @@ "dependencies": { "JorgeSerrano.Json.JsonSnakeCaseNamingPolicy": "[0.9.0, )", "NLog": "[5.1.0, )", - "SemanticVersioning": "[2.0.2, )" + "NuGet.Commands": "[6.4.0, )", + "NuGet.DependencyResolver.Core": "[6.4.0, )", + "SemanticVersioning": "[2.0.2, )", + "System.Linq.Async": "[6.0.1, )" } } }