diff --git a/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs b/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs index 3d6311c110..b552008c30 100644 --- a/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs +++ b/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs @@ -3,6 +3,7 @@ using System.Reactive.Linq; using DynamicData.Binding; using JetBrains.Annotations; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NexusMods.Abstractions.MnemonicDB.Attributes; using NexusMods.Abstractions.NexusWebApi; @@ -19,14 +20,15 @@ namespace NexusMods.Networking.NexusWebApi; /// Component for handling login and logout from the Nexus Mods /// [PublicAPI] -public sealed class LoginManager : IDisposable, ILoginManager +public sealed class LoginManager : IDisposable, ILoginManager, IHostedService { private readonly ILogger _logger; private readonly OAuth _oauth; private readonly IProtocolRegistration _protocolRegistration; private readonly NexusApiClient _nexusApiClient; private readonly IAuthenticatingMessageFactory _msgFactory; - + private Task? _startupTask = null; + private CompositeDisposable _subscriptions = new CompositeDisposable(); @@ -173,4 +175,30 @@ public void Dispose() _verifySemaphore.Dispose(); _subscriptions.Dispose(); } + + /// + public async Task StartAsync(CancellationToken cancellationToken) + { + lock (this) + { + _startupTask ??= Startup(cancellationToken); + } + await _startupTask; + } + + private async Task Startup(CancellationToken cancellationToken) + { + await ((IHostedService)_jwtTokenRepository).StartAsync(cancellationToken); + var userInfo = await Verify(cancellationToken); + if (userInfo is not null) + { + UserInfo = userInfo; + } + } + + /// + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } } diff --git a/src/Networking/NexusMods.Networking.NexusWebApi/Services.cs b/src/Networking/NexusMods.Networking.NexusWebApi/Services.cs index 5384d8f0dc..190139bf07 100644 --- a/src/Networking/NexusMods.Networking.NexusWebApi/Services.cs +++ b/src/Networking/NexusMods.Networking.NexusWebApi/Services.cs @@ -46,6 +46,7 @@ public static IServiceCollection AddNexusWebApi(this IServiceCollection collecti return collection .AddAllSingleton() + .AddHostedService(s => (LoginManager)s.GetRequiredService()) .AddAllSingleton() .AddNexusApiVerbs(); } diff --git a/src/NexusMods.App/Program.cs b/src/NexusMods.App/Program.cs index 1b54d8519d..cf52d8544a 100644 --- a/src/NexusMods.App/Program.cs +++ b/src/NexusMods.App/Program.cs @@ -61,6 +61,10 @@ public static int Main(string[] args) // Okay to do wait here, as we are in the main process thread. host.StartAsync().Wait(timeout: TimeSpan.FromMinutes(5)); + + // Start the CLI server if we are the main process. + var cliServer = services.GetService(); + cliServer?.StartCliServerAsync().Wait(timeout: TimeSpan.FromSeconds(5)); _logger = services.GetRequiredService>(); LogMessages.RuntimeInformation(_logger, RuntimeInformation.OSDescription, RuntimeInformation.FrameworkDescription); diff --git a/src/NexusMods.App/Services.cs b/src/NexusMods.App/Services.cs index a78e9b0f97..c074d2dbf7 100644 --- a/src/NexusMods.App/Services.cs +++ b/src/NexusMods.App/Services.cs @@ -93,7 +93,8 @@ public static IServiceCollection AddApp(this IServiceCollection services, services.AddFileSystem() .AddCrossPlatform() .AddDefaultRenderers() - .AddSettingsManager(); + .AddSettingsManager() + .AddSettings(); if (!startupMode.IsAvaloniaDesigner) services.AddSingleProcess(Mode.Client); diff --git a/src/NexusMods.SingleProcess/CliServer.cs b/src/NexusMods.SingleProcess/CliServer.cs index 90bd01e8b3..4db6e6568f 100644 --- a/src/NexusMods.SingleProcess/CliServer.cs +++ b/src/NexusMods.SingleProcess/CliServer.cs @@ -1,9 +1,7 @@ using System.Net; using System.Net.Sockets; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using NexusMods.Abstractions.GameLocators; using NexusMods.Abstractions.Settings; using NexusMods.ProxyConsole; using NexusMods.SingleProcess.Exceptions; @@ -49,6 +47,19 @@ public CliServer( _settings = settingsManager.Get(); } + + /// + /// Starts the CLI server, listening for incoming connections. + /// This method needs to be called explicitly to start the server. + /// + public async Task StartCliServerAsync() + { + if (!_started) + { + _started = true; + await StartTcpListenerAsync(); + } + } private Task StartTcpListenerAsync() { @@ -135,19 +146,11 @@ private void CleanClosedConnections() _runningClients.Remove(task); } } - + /// - public async Task StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken) { - // Bit of a hack, but works for now till we get better startup logic with DI - var registry = _serviceProvider.GetRequiredService(); - await ((IHostedService)registry).StartAsync(cancellationToken); - - if (!_started && _settings.StartCliBackend) - { - _started = true; - await StartTcpListenerAsync(); - } + return Task.CompletedTask; } /// diff --git a/src/NexusMods.SingleProcess/Services.cs b/src/NexusMods.SingleProcess/Services.cs index 9cf62e30c4..8ff5fc0638 100644 --- a/src/NexusMods.SingleProcess/Services.cs +++ b/src/NexusMods.SingleProcess/Services.cs @@ -33,6 +33,7 @@ public static IServiceCollection AddSingleProcess(this IServiceCollection servic switch (mode) { case Mode.Main: + services.AddSingleton(); services.AddHostedService(); break; case Mode.Client: diff --git a/tests/Games/NexusMods.Games.BethesdaGameStudios.Tests/Startup.cs b/tests/Games/NexusMods.Games.BethesdaGameStudios.Tests/Startup.cs index e870f9d132..e0796d68b2 100644 --- a/tests/Games/NexusMods.Games.BethesdaGameStudios.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.BethesdaGameStudios.Tests/Startup.cs @@ -29,7 +29,6 @@ public void ConfigureServices(IServiceCollection services) .AddSingleton() .AddBethesdaGameStudios() .AddGames() - .AddActivityMonitor() .AddSerializationAbstractions() .AddInstallerTypes() .AddGenericGameSupport() @@ -39,7 +38,6 @@ public void ConfigureServices(IServiceCollection services) .AddCLI() .AddSingleton() .AddLogging(builder => builder.AddXunitOutput()) - .AddCrossPlatform() .Validate(); } } diff --git a/tests/Games/NexusMods.Games.BladeAndSorcery.Tests/Startup.cs b/tests/Games/NexusMods.Games.BladeAndSorcery.Tests/Startup.cs index 6dad32d29e..fcc1f714c9 100644 --- a/tests/Games/NexusMods.Games.BladeAndSorcery.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.BladeAndSorcery.Tests/Startup.cs @@ -25,10 +25,8 @@ public void ConfigureServices(IServiceCollection container) .AddGames() .AddFileStoreAbstractions() .AddLoadoutAbstractions() - .AddActivityMonitor() .AddSerializationAbstractions() .AddInstallerTypes() - .AddCrossPlatform() .Validate(); } } diff --git a/tests/Games/NexusMods.Games.DarkestDungeon.Tests/Startup.cs b/tests/Games/NexusMods.Games.DarkestDungeon.Tests/Startup.cs index 64f44d2714..7ed91eb095 100644 --- a/tests/Games/NexusMods.Games.DarkestDungeon.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.DarkestDungeon.Tests/Startup.cs @@ -23,12 +23,10 @@ public void ConfigureServices(IServiceCollection container) .AddDarkestDungeon() .AddLogging(builder => builder.AddXUnit()) .AddGames() - .AddActivityMonitor() .AddFileStoreAbstractions() .AddLoadoutAbstractions() .AddSerializationAbstractions() .AddInstallerTypes() - .AddCrossPlatform() .Validate(); } } diff --git a/tests/Games/NexusMods.Games.FOMOD.Tests/Startup.cs b/tests/Games/NexusMods.Games.FOMOD.Tests/Startup.cs index 83ff35a7dc..b77a668089 100644 --- a/tests/Games/NexusMods.Games.FOMOD.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.FOMOD.Tests/Startup.cs @@ -6,7 +6,6 @@ using NexusMods.Abstractions.Installers; using NexusMods.Abstractions.Loadouts; using NexusMods.Abstractions.Serialization; -using NexusMods.Activities; using NexusMods.App.BuildInfo; using NexusMods.CrossPlatform; using NexusMods.Games.BethesdaGameStudios; @@ -23,7 +22,6 @@ public class Startup public void ConfigureServices(IServiceCollection container) { container - .AddCrossPlatform() .AddLoadoutAbstractions() .AddDefaultServicesForTesting() .AddBethesdaGameStudios() @@ -34,7 +32,6 @@ public void ConfigureServices(IServiceCollection container) .AddSingleton() .AddLogging(builder => builder.AddXunitOutput().SetMinimumLevel(LogLevel.Debug)) .AddGames() - .AddActivityMonitor() .AddSerializationAbstractions() .AddInstallerTypes() .Validate(); diff --git a/tests/Games/NexusMods.Games.MountAndBlade2Bannerlord.Tests/Startup.cs b/tests/Games/NexusMods.Games.MountAndBlade2Bannerlord.Tests/Startup.cs index d0ea5e70eb..fcb650e059 100644 --- a/tests/Games/NexusMods.Games.MountAndBlade2Bannerlord.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.MountAndBlade2Bannerlord.Tests/Startup.cs @@ -23,12 +23,10 @@ public void ConfigureServices(IServiceCollection services) .AddMountAndBladeBannerlord() .AddLogging(builder => builder.AddXunitOutput()) .AddGames() - .AddActivityMonitor() .AddSerializationAbstractions() .AddFileStoreAbstractions() .AddLoadoutAbstractions() .AddInstallerTypes() - .AddCrossPlatform() .Validate(); } } diff --git a/tests/Games/NexusMods.Games.RedEngine.Tests/Startup.cs b/tests/Games/NexusMods.Games.RedEngine.Tests/Startup.cs index a0bb3dacb9..cd1d2116b8 100644 --- a/tests/Games/NexusMods.Games.RedEngine.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.RedEngine.Tests/Startup.cs @@ -23,12 +23,10 @@ public void ConfigureServices(IServiceCollection container) .AddRedEngineGames() .AddLogging(builder => builder.AddXUnit()) .AddGames() - .AddActivityMonitor() .AddSerializationAbstractions() .AddLoadoutAbstractions() .AddFileStoreAbstractions() .AddInstallerTypes() - .AddCrossPlatform() .Validate(); } } diff --git a/tests/Games/NexusMods.Games.Sifu.Tests/Startup.cs b/tests/Games/NexusMods.Games.Sifu.Tests/Startup.cs index 8b7bec0579..21cbe842bb 100644 --- a/tests/Games/NexusMods.Games.Sifu.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.Sifu.Tests/Startup.cs @@ -23,12 +23,10 @@ public void ConfigureServices(IServiceCollection container) .AddSifu() .AddLogging(builder => builder.AddXUnit()) .AddGames() - .AddActivityMonitor() .AddFileStoreAbstractions() .AddLoadoutAbstractions() .AddSerializationAbstractions() .AddInstallerTypes() - .AddCrossPlatform() .Validate(); } } diff --git a/tests/Games/NexusMods.Games.StardewValley.Tests/Startup.cs b/tests/Games/NexusMods.Games.StardewValley.Tests/Startup.cs index 4052049d8f..d3ec57beb8 100644 --- a/tests/Games/NexusMods.Games.StardewValley.Tests/Startup.cs +++ b/tests/Games/NexusMods.Games.StardewValley.Tests/Startup.cs @@ -29,12 +29,10 @@ public void ConfigureServices(IServiceCollection container) .AddStardewValley() .AddLogging(builder => builder.AddXUnit()) .AddGames() - .AddActivityMonitor() .AddFileStoreAbstractions() .AddLoadoutAbstractions() .AddSerializationAbstractions() .AddInstallerTypes() - .AddCrossPlatform() .Validate(); } } diff --git a/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs b/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs index 333a63b094..a63a7064c3 100644 --- a/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs +++ b/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs @@ -2,9 +2,11 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using NexusMods.Abstractions.Activities; using NexusMods.Abstractions.HttpDownloader; using NexusMods.Abstractions.Loadouts.Synchronizers; using NexusMods.Abstractions.Settings; +using NexusMods.Activities; using NexusMods.CrossPlatform; using NexusMods.DataModel; using NexusMods.FileExtractor; @@ -52,6 +54,9 @@ public static IServiceCollection AddDefaultServicesForTesting(this IServiceColle .AddSingleton() .AddSingleton() .AddNexusWebApi(true) + .AddCrossPlatform() + .AddActivityMonitor() + .AddSettings() .AddHttpDownloader() .AddDataModel() .AddLoadoutsSynchronizers() diff --git a/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj b/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj index d7de6965c9..c3b104b69a 100644 --- a/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj +++ b/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj @@ -3,6 +3,7 @@ + diff --git a/tests/Networking/NexusMods.Networking.Downloaders.Tests/Startup.cs b/tests/Networking/NexusMods.Networking.Downloaders.Tests/Startup.cs index 11fc078ed8..46d473a40f 100644 --- a/tests/Networking/NexusMods.Networking.Downloaders.Tests/Startup.cs +++ b/tests/Networking/NexusMods.Networking.Downloaders.Tests/Startup.cs @@ -2,8 +2,10 @@ using NexusMods.Abstractions.GuidedInstallers; using NexusMods.Abstractions.Serialization; using NexusMods.Abstractions.Serialization.ExpressionGenerator; +using NexusMods.Abstractions.Settings; using NexusMods.Activities; using NexusMods.App.BuildInfo; +using NexusMods.CrossPlatform; using NexusMods.Extensions.DependencyInjection; using NexusMods.Games.BethesdaGameStudios; using NexusMods.Games.BethesdaGameStudios.SkyrimSpecialEdition; @@ -26,7 +28,6 @@ public void ConfigureServices(IServiceCollection services) .AddDefaultServicesForTesting() .AddUniversalGameLocator(new Version("1.61")) .AddUniversalGameLocator(new Version("1.6.659.0")) - .AddActivityMonitor() .AddStubbedGameLocators() .AddBethesdaGameStudios() .AddGenericGameSupport() diff --git a/tests/Networking/NexusMods.Networking.NexusWebApi.Tests/Startup.cs b/tests/Networking/NexusMods.Networking.NexusWebApi.Tests/Startup.cs index e5d91a02ba..9db3d4b3fd 100644 --- a/tests/Networking/NexusMods.Networking.NexusWebApi.Tests/Startup.cs +++ b/tests/Networking/NexusMods.Networking.NexusWebApi.Tests/Startup.cs @@ -1,8 +1,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NexusMods.Abstractions.Loadouts; +using NexusMods.Abstractions.Settings; using NexusMods.Activities; using NexusMods.App.BuildInfo; +using NexusMods.CrossPlatform; using NexusMods.CrossPlatform.Process; using NexusMods.DataModel; using NexusMods.Networking.HttpDownloader; @@ -23,10 +25,11 @@ public void ConfigureServices(IServiceCollection services) .AddSingleton() .AddHttpDownloader() .AddSingleton() - .AddSingleton() .AddSingleton() .AddNexusWebApi(true) .AddActivityMonitor() + .AddCrossPlatform() + .AddSettings() .AddLoadoutAbstractions() .AddDataModel() // this is required because we're also using NMA integration .AddLogging(builder => builder.AddXunitOutput() diff --git a/tests/NexusMods.CLI.Tests/Startup.cs b/tests/NexusMods.CLI.Tests/Startup.cs index 6e9ec79025..297729ccd0 100644 --- a/tests/NexusMods.CLI.Tests/Startup.cs +++ b/tests/NexusMods.CLI.Tests/Startup.cs @@ -49,6 +49,7 @@ public void ConfigureServices(IServiceCollection services) .AddGames() .AddInstallerTypes() .AddCrossPlatform() + .AddSettings() .AddLogging(builder => builder.AddXunitOutput().SetMinimumLevel(LogLevel.Trace)) .AddSingleton() .AddLogging(builder => builder.AddXUnit())