diff --git a/NexusMods.App.sln b/NexusMods.App.sln
index 5086507845..53661c13bd 100644
--- a/NexusMods.App.sln
+++ b/NexusMods.App.sln
@@ -214,7 +214,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interprocess", "Interproces
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Settings.Tests", "tests\NexusMods.Settings.Tests\NexusMods.Settings.Tests.csproj", "{0D289DCE-1B17-4B63-B8B3-47CB852BF5B4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Abstractions.Library", "src\Abstractions\NexusMods.Abstractions.Library\NexusMods.Abstractions.Library.csproj", "{0044D340-E435-489C-A425-139AAB2EA205}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Abstractions.Library.Models", "src\Abstractions\NexusMods.Abstractions.Library.Models\NexusMods.Abstractions.Library.Models.csproj", "{0044D340-E435-489C-A425-139AAB2EA205}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Abstractions.NexusModsLibrary", "src\Abstractions\NexusMods.Abstractions.NexusModsLibrary\NexusMods.Abstractions.NexusModsLibrary.csproj", "{5D85EBB2-755F-4148-BFC4-8D2245A3105B}"
EndProject
@@ -228,6 +228,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Abstractions.Jobs
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Jobs.Tests", "tests\NexusMods.Jobs.Tests\NexusMods.Jobs.Tests.csproj", "{01043F6A-121B-4B3C-A694-B823D9CD0BB0}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Abstractions.Library", "src\Abstractions\NexusMods.Abstractions.Library\NexusMods.Abstractions.Library.csproj", "{C47C59F4-1C6C-4F78-9A27-F328F1C02BF0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Jobs", "src\NexusMods.Jobs\NexusMods.Jobs.csproj", "{44E6BD8A-7A82-49CC-91FA-AF3B3E5FBEE9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NexusMods.Abstractions.Library.Installers", "src\Abstractions\NexusMods.Abstractions.Library.Installers\NexusMods.Abstractions.Library.Installers.csproj", "{F6482055-698C-492A-9FC2-0FCDC9FC2E23}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -586,6 +592,18 @@ Global
{01043F6A-121B-4B3C-A694-B823D9CD0BB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01043F6A-121B-4B3C-A694-B823D9CD0BB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01043F6A-121B-4B3C-A694-B823D9CD0BB0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C47C59F4-1C6C-4F78-9A27-F328F1C02BF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C47C59F4-1C6C-4F78-9A27-F328F1C02BF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C47C59F4-1C6C-4F78-9A27-F328F1C02BF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C47C59F4-1C6C-4F78-9A27-F328F1C02BF0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {44E6BD8A-7A82-49CC-91FA-AF3B3E5FBEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {44E6BD8A-7A82-49CC-91FA-AF3B3E5FBEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {44E6BD8A-7A82-49CC-91FA-AF3B3E5FBEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {44E6BD8A-7A82-49CC-91FA-AF3B3E5FBEE9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F6482055-698C-492A-9FC2-0FCDC9FC2E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F6482055-698C-492A-9FC2-0FCDC9FC2E23}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F6482055-698C-492A-9FC2-0FCDC9FC2E23}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F6482055-698C-492A-9FC2-0FCDC9FC2E23}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -690,6 +708,9 @@ Global
{821C1DA9-040E-44F3-BFCA-BF026C3F254B} = {0CB73565-1207-4A56-A79F-6A8E9BBD795C}
{D15413CA-E727-40DA-8CD8-29ED052BF427} = {0CB73565-1207-4A56-A79F-6A8E9BBD795C}
{01043F6A-121B-4B3C-A694-B823D9CD0BB0} = {52AF9D62-7D5B-4AD0-BA12-86F2AA67428B}
+ {C47C59F4-1C6C-4F78-9A27-F328F1C02BF0} = {0CB73565-1207-4A56-A79F-6A8E9BBD795C}
+ {44E6BD8A-7A82-49CC-91FA-AF3B3E5FBEE9} = {E7BAE287-D505-4D6D-A090-665A64309B2D}
+ {F6482055-698C-492A-9FC2-0FCDC9FC2E23} = {0CB73565-1207-4A56-A79F-6A8E9BBD795C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F9F8352-34DD-42C0-8564-EE9AF34A3501}
diff --git a/src/Abstractions/NexusMods.Abstractions.Games/AGame.cs b/src/Abstractions/NexusMods.Abstractions.Games/AGame.cs
index 9f3ad2b107..1263b63f28 100644
--- a/src/Abstractions/NexusMods.Abstractions.Games/AGame.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Games/AGame.cs
@@ -7,6 +7,7 @@
using NexusMods.Abstractions.Games.Loadouts;
using NexusMods.Abstractions.Installers;
using NexusMods.Abstractions.IO;
+using NexusMods.Abstractions.Library.Installers;
using NexusMods.Abstractions.Loadouts.Mods;
using NexusMods.Abstractions.Loadouts.Synchronizers;
using NexusMods.Abstractions.Serialization;
@@ -70,6 +71,9 @@ protected virtual ILoadoutSynchronizer MakeSynchronizer(IServiceProvider provide
///
public virtual IEnumerable Installers => _installers.Value;
+ ///
+ public virtual ILibraryItemInstaller[] LibraryItemInstallers { get; } = [];
+
///
public virtual IDiagnosticEmitter[] DiagnosticEmitters { get; } = Array.Empty();
diff --git a/src/Abstractions/NexusMods.Abstractions.Games/IGame.cs b/src/Abstractions/NexusMods.Abstractions.Games/IGame.cs
index 5edec419d5..92023f7625 100644
--- a/src/Abstractions/NexusMods.Abstractions.Games/IGame.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Games/IGame.cs
@@ -2,6 +2,7 @@
using NexusMods.Abstractions.GameLocators;
using NexusMods.Abstractions.Installers;
using NexusMods.Abstractions.IO;
+using NexusMods.Abstractions.Library.Installers;
using NexusMods.Abstractions.Loadouts.Mods;
using NexusMods.Abstractions.Loadouts.Synchronizers;
using NexusMods.Abstractions.Serialization;
@@ -31,6 +32,11 @@ public interface IGame : ILocatableGame
///
public IEnumerable Installers { get; }
+ ///
+ /// Gets all available installers this game supports.
+ ///
+ public ILibraryItemInstaller[] LibraryItemInstallers { get; }
+
///
/// An array of all instances of supported
/// by the game.
diff --git a/src/Abstractions/NexusMods.Abstractions.Games/NexusMods.Abstractions.Games.csproj b/src/Abstractions/NexusMods.Abstractions.Games/NexusMods.Abstractions.Games.csproj
index d16acbb31a..161b992b82 100644
--- a/src/Abstractions/NexusMods.Abstractions.Games/NexusMods.Abstractions.Games.csproj
+++ b/src/Abstractions/NexusMods.Abstractions.Games/NexusMods.Abstractions.Games.csproj
@@ -24,6 +24,7 @@
+
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/Extensions.cs b/src/Abstractions/NexusMods.Abstractions.Installers/Extensions.cs
index 2f4851e77d..c899a23a7e 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/Extensions.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Installers/Extensions.cs
@@ -1,9 +1,6 @@
-using System.Collections.Immutable;
using NexusMods.Abstractions.FileStore.Trees;
using NexusMods.Abstractions.GameLocators;
using NexusMods.Abstractions.Loadouts.Files;
-using NexusMods.Abstractions.Loadouts.Mods;
-using NexusMods.Abstractions.Serialization;
using NexusMods.MnemonicDB.Abstractions.Models;
using NexusMods.Paths;
using NexusMods.Paths.Trees;
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/IArchiveInstaller.cs b/src/Abstractions/NexusMods.Abstractions.Installers/IArchiveInstaller.cs
index c7a1a044df..b7c6dba0ad 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/IArchiveInstaller.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Installers/IArchiveInstaller.cs
@@ -1,7 +1,6 @@
using NexusMods.Abstractions.Activities;
using NexusMods.Abstractions.FileStore.Downloads;
using NexusMods.Abstractions.Loadouts;
-using NexusMods.Abstractions.Loadouts.Ids;
using NexusMods.Abstractions.Loadouts.Mods;
namespace NexusMods.Abstractions.Installers;
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerInfo.cs b/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerInfo.cs
index 0708b0bd80..baa7ad4b11 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerInfo.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerInfo.cs
@@ -1,8 +1,6 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.FileStore.ArchiveMetadata;
using NexusMods.Abstractions.FileStore.Downloads;
using NexusMods.Abstractions.GameLocators;
-using NexusMods.Abstractions.Loadouts.Ids;
using NexusMods.Abstractions.Loadouts.Mods;
using ModFileTreeNode = NexusMods.Paths.Trees.KeyedBox;
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerResult.cs b/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerResult.cs
index 4729381f5a..f3cb3d4ac0 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerResult.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Installers/ModInstallerResult.cs
@@ -1,6 +1,4 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.DataModel.Entities.Sorting;
-using NexusMods.Abstractions.Loadouts.Ids;
using NexusMods.Abstractions.Loadouts.Mods;
using NexusMods.MnemonicDB.Abstractions.Models;
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/NexusMods.Abstractions.Installers.csproj b/src/Abstractions/NexusMods.Abstractions.Installers/NexusMods.Abstractions.Installers.csproj
index d7cee6417e..fa3af61b3d 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/NexusMods.Abstractions.Installers.csproj
+++ b/src/Abstractions/NexusMods.Abstractions.Installers/NexusMods.Abstractions.Installers.csproj
@@ -3,7 +3,6 @@
-
@@ -16,21 +15,6 @@
-
- ILibraryItemInstaller.cs
-
-
- ILibraryItemInstaller.cs
-
-
- ILibraryItemInstaller.cs
-
-
- ILibraryFileInstaller.cs
-
-
- ILibraryArchiveInstaller.cs
-
IModInstaller.cs
diff --git a/src/Abstractions/NexusMods.Abstractions.Jobs/AJob.cs b/src/Abstractions/NexusMods.Abstractions.Jobs/AJob.cs
index 26ddaecb4a..53f9b45691 100644
--- a/src/Abstractions/NexusMods.Abstractions.Jobs/AJob.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Jobs/AJob.cs
@@ -42,7 +42,8 @@ public abstract class AJob : IJobGroup, IDisposable, IAsyncDisposable
protected AJob(
MutableProgress progress,
IJobGroup? group = default,
- IJobWorker? worker = default)
+ IJobWorker? worker = default,
+ IJobMonitor? monitor = default)
{
Id = JobId.NewId();
Status = JobStatus.None;
@@ -64,6 +65,8 @@ protected AJob(
_collection = [];
_observableCollection = new ObservableCollection(_collection);
ObservableCollection = new ReadOnlyObservableCollection(_observableCollection);
+
+ monitor?.RegisterJob(this);
}
public IEnumerator GetEnumerator() => _collection.GetEnumerator();
diff --git a/src/Abstractions/NexusMods.Abstractions.Jobs/IJobMonitor.cs b/src/Abstractions/NexusMods.Abstractions.Jobs/IJobMonitor.cs
new file mode 100644
index 0000000000..91592501ee
--- /dev/null
+++ b/src/Abstractions/NexusMods.Abstractions.Jobs/IJobMonitor.cs
@@ -0,0 +1,27 @@
+using System.Collections.ObjectModel;
+using DynamicData;
+using JetBrains.Annotations;
+
+namespace NexusMods.Abstractions.Jobs;
+
+///
+/// Represents a monitor for jobs.
+///
+[PublicAPI]
+public interface IJobMonitor
+{
+ ///
+ /// Gets an observable collection containing every job the monitor knows about.
+ ///
+ ReadOnlyObservableCollection Jobs { get; }
+
+ ///
+ /// Gets an observable with changeset for jobs of type .
+ ///
+ IObservable> GetObservableChangeSet() where TJob : IJob;
+
+ ///
+ /// Registers a job with the monitor.
+ ///
+ void RegisterJob(IJob job);
+}
diff --git a/src/Abstractions/NexusMods.Abstractions.Jobs/JobResult.cs b/src/Abstractions/NexusMods.Abstractions.Jobs/JobResult.cs
index 8b082bf9c7..e5f85bdd09 100644
--- a/src/Abstractions/NexusMods.Abstractions.Jobs/JobResult.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Jobs/JobResult.cs
@@ -78,18 +78,25 @@ public bool TryGetFailed([NotNullWhen(true)] out JobResultFailed? failed)
return true;
}
+ ///
+ /// Returns the data in the completed result or thrown an exception.
+ ///
+ /// The result isn't of type
public TData RequireData()
where TData : notnull
{
if (!TryGetCompleted(out var completed))
- throw new InvalidOperationException($"JobResult is of type `{ResultType}` but expected `{JobResultType.Completed}`");
+ throw new InvalidOperationException($"JobResult is of type `{ResultType}` but expected `{JobResultType.Completed}`: `{ToString()}`");
if (!completed.TryGetData(out var data))
- throw new InvalidOperationException("Completed JobResult doesn't have data!");
+ throw new InvalidOperationException($"Completed JobResult doesn't have data: `{ToString()}`");
return data;
}
+ ///
+ /// Creates a failed job result from an exception.
+ ///
[StackTraceHidden]
public static JobResult CreateFailed(Exception exception)
{
@@ -99,15 +106,23 @@ public static JobResult CreateFailed(Exception exception)
});
}
+ ///
+ /// Creates a failed job result from an error message.
+ ///
[StackTraceHidden]
public static JobResult CreateFailed(string message)
{
return CreateFailed(new Exception(message));
}
+ ///
+ /// Creates a cancelled job result.
+ ///
[StackTraceHidden] public static JobResult CreateCancelled() => new(new JobResultCancelled());
- [StackTraceHidden] public static JobResult CreateCompleted() => new(new JobResultCompleted());
+ ///
+ /// Creates a completed job result with data.
+ ///
[StackTraceHidden]
public static JobResult CreateCompleted(TData data)
where TData : notnull
@@ -117,4 +132,14 @@ public static JobResult CreateCompleted(TData data)
Data = data,
});
}
+
+ ///
+ public override string ToString()
+ {
+ return _value.Match(
+ f0: x => x.ToString(),
+ f1: x => x.ToString(),
+ f2: x => x.ToString()
+ );
+ }
}
diff --git a/src/Abstractions/NexusMods.Abstractions.Jobs/JobWorker.cs b/src/Abstractions/NexusMods.Abstractions.Jobs/JobWorker.cs
index 1a62d3f384..2099b49caa 100644
--- a/src/Abstractions/NexusMods.Abstractions.Jobs/JobWorker.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Jobs/JobWorker.cs
@@ -12,7 +12,7 @@ public delegate Task ExecuteAsyncDelegateWithData(TJob job,
public delegate Task ExecuteAsyncDelegate(TJob job, AJobWorker worker, CancellationToken cancellationToken)
where TJob : AJob;
- public static AJobWorker Create(TJob job, ExecuteAsyncDelegateWithData func)
+ public static AJobWorker CreateWithData(TJob job, ExecuteAsyncDelegateWithData func)
where TJob : AJob
where TData : notnull
{
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ALibraryArchiveInstaller.cs b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryArchiveInstaller.cs
similarity index 95%
rename from src/Abstractions/NexusMods.Abstractions.Installers/ALibraryArchiveInstaller.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryArchiveInstaller.cs
index b503cb9e2c..e93d9ed50e 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ALibraryArchiveInstaller.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryArchiveInstaller.cs
@@ -1,10 +1,10 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.MnemonicDB.Abstractions;
-namespace NexusMods.Abstractions.Installers;
+namespace NexusMods.Abstractions.Library.Installers;
///
/// Base implementation of .
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ALibraryFileInstaller.cs b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryFileInstaller.cs
similarity index 95%
rename from src/Abstractions/NexusMods.Abstractions.Installers/ALibraryFileInstaller.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryFileInstaller.cs
index 601542c220..1eb1014ec9 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ALibraryFileInstaller.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryFileInstaller.cs
@@ -1,10 +1,10 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.MnemonicDB.Abstractions;
-namespace NexusMods.Abstractions.Installers;
+namespace NexusMods.Abstractions.Library.Installers;
///
/// Base implementation of .
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ALibraryItemInstaller.cs b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryItemInstaller.cs
similarity index 92%
rename from src/Abstractions/NexusMods.Abstractions.Installers/ALibraryItemInstaller.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryItemInstaller.cs
index 58420b4ca2..3bd3e49755 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ALibraryItemInstaller.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ALibraryItemInstaller.cs
@@ -1,10 +1,10 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.MnemonicDB.Abstractions;
-namespace NexusMods.Abstractions.Installers;
+namespace NexusMods.Abstractions.Library.Installers;
///
/// Base implementation of .
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ILibraryArchiveInstaller.cs b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryArchiveInstaller.cs
similarity index 89%
rename from src/Abstractions/NexusMods.Abstractions.Installers/ILibraryArchiveInstaller.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryArchiveInstaller.cs
index d5fe51ba66..0d2f4a6fdd 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ILibraryArchiveInstaller.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryArchiveInstaller.cs
@@ -1,9 +1,9 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.MnemonicDB.Abstractions;
-namespace NexusMods.Abstractions.Installers;
+namespace NexusMods.Abstractions.Library.Installers;
///
/// Variant of for
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ILibraryFileInstaller.cs b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryFileInstaller.cs
similarity index 89%
rename from src/Abstractions/NexusMods.Abstractions.Installers/ILibraryFileInstaller.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryFileInstaller.cs
index 1128ba3369..14d85f606b 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ILibraryFileInstaller.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryFileInstaller.cs
@@ -1,9 +1,9 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.MnemonicDB.Abstractions;
-namespace NexusMods.Abstractions.Installers;
+namespace NexusMods.Abstractions.Library.Installers;
///
/// Variant of for .
diff --git a/src/Abstractions/NexusMods.Abstractions.Installers/ILibraryItemInstaller.cs b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryItemInstaller.cs
similarity index 88%
rename from src/Abstractions/NexusMods.Abstractions.Installers/ILibraryItemInstaller.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryItemInstaller.cs
index 29d5d73887..d7f2020116 100644
--- a/src/Abstractions/NexusMods.Abstractions.Installers/ILibraryItemInstaller.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Installers/ILibraryItemInstaller.cs
@@ -1,9 +1,9 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.MnemonicDB.Abstractions;
-namespace NexusMods.Abstractions.Installers;
+namespace NexusMods.Abstractions.Library.Installers;
///
/// Turns into .
diff --git a/src/Abstractions/NexusMods.Abstractions.Library.Installers/NexusMods.Abstractions.Library.Installers.csproj b/src/Abstractions/NexusMods.Abstractions.Library.Installers/NexusMods.Abstractions.Library.Installers.csproj
new file mode 100644
index 0000000000..c87c227886
--- /dev/null
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Installers/NexusMods.Abstractions.Library.Installers.csproj
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ILibraryArchiveInstaller.cs
+
+
+ ILibraryFileInstaller.cs
+
+
+ ILibraryItemInstaller.cs
+
+
+
+
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/LibraryArchive.cs b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryArchive.cs
similarity index 93%
rename from src/Abstractions/NexusMods.Abstractions.Library/LibraryArchive.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryArchive.cs
index 0a4957a5b5..18fa778547 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/LibraryArchive.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryArchive.cs
@@ -2,7 +2,7 @@
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
-namespace NexusMods.Abstractions.Library;
+namespace NexusMods.Abstractions.Library.Models;
///
/// Represents an archive in the library.
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/LibraryArchiveFileEntry.cs b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryArchiveFileEntry.cs
similarity index 86%
rename from src/Abstractions/NexusMods.Abstractions.Library/LibraryArchiveFileEntry.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryArchiveFileEntry.cs
index 18ca85ec87..e094149485 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/LibraryArchiveFileEntry.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryArchiveFileEntry.cs
@@ -1,9 +1,8 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
-namespace NexusMods.Abstractions.Library;
+namespace NexusMods.Abstractions.Library.Models;
///
/// Represents a file inside a library archive.
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/LibraryFile.cs b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryFile.cs
similarity index 94%
rename from src/Abstractions/NexusMods.Abstractions.Library/LibraryFile.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryFile.cs
index e5821acc8c..ef268c7bd8 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/LibraryFile.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryFile.cs
@@ -2,7 +2,7 @@
using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
-namespace NexusMods.Abstractions.Library;
+namespace NexusMods.Abstractions.Library.Models;
///
/// Represents a that is a file in the library.
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/LibraryItem.cs b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryItem.cs
similarity index 90%
rename from src/Abstractions/NexusMods.Abstractions.Library/LibraryItem.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryItem.cs
index 1ebd1c30b0..2fd3674994 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/LibraryItem.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Models/LibraryItem.cs
@@ -2,7 +2,7 @@
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
-namespace NexusMods.Abstractions.Library;
+namespace NexusMods.Abstractions.Library.Models;
///
/// Represents an item in the library.
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/LocalFile.cs b/src/Abstractions/NexusMods.Abstractions.Library.Models/LocalFile.cs
similarity index 92%
rename from src/Abstractions/NexusMods.Abstractions.Library/LocalFile.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Models/LocalFile.cs
index 0b94a808cd..21617cf340 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/LocalFile.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Models/LocalFile.cs
@@ -2,7 +2,7 @@
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
-namespace NexusMods.Abstractions.Library;
+namespace NexusMods.Abstractions.Library.Models;
///
/// Represents a local file in the library.
diff --git a/src/Abstractions/NexusMods.Abstractions.Library.Models/NexusMods.Abstractions.Library.Models.csproj b/src/Abstractions/NexusMods.Abstractions.Library.Models/NexusMods.Abstractions.Library.Models.csproj
new file mode 100644
index 0000000000..b27970d59b
--- /dev/null
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Models/NexusMods.Abstractions.Library.Models.csproj
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LibraryItem.cs
+
+
+ LibraryItem.cs
+
+
+ LibraryArchive.cs
+
+
+
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/Services.cs b/src/Abstractions/NexusMods.Abstractions.Library.Models/Services.cs
similarity index 85%
rename from src/Abstractions/NexusMods.Abstractions.Library/Services.cs
rename to src/Abstractions/NexusMods.Abstractions.Library.Models/Services.cs
index 33a0624467..c0e2a7e836 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/Services.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library.Models/Services.cs
@@ -1,8 +1,7 @@
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
-using NexusMods.Abstractions.MnemonicDB.Attributes;
-namespace NexusMods.Abstractions.Library;
+namespace NexusMods.Abstractions.Library.Models;
///
/// Extension methods.
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/ILibraryService.cs b/src/Abstractions/NexusMods.Abstractions.Library/ILibraryService.cs
index 67702580f5..1dee0edf14 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/ILibraryService.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Library/ILibraryService.cs
@@ -1,6 +1,9 @@
using JetBrains.Annotations;
+using NexusMods.Abstractions.Downloads;
using NexusMods.Abstractions.Jobs;
+using NexusMods.Abstractions.Loadouts;
using NexusMods.Paths;
+using LibraryItem = NexusMods.Abstractions.Library.Models.LibraryItem;
namespace NexusMods.Abstractions.Library;
@@ -10,8 +13,20 @@ namespace NexusMods.Abstractions.Library;
[PublicAPI]
public interface ILibraryService
{
+ ///
+ /// Adds a download to the library.
+ ///
+ IJob AddDownload(IDownloadJob downloadJob);
+
///
/// Adds a local file to the library.
///
IJob AddLocalFile(AbsolutePath absolutePath);
+
+ ///
+ /// Installs a library item into a target loadout.
+ ///
+ /// The item to install.
+ /// The target loadout.
+ IJob InstallItem(LibraryItem.ReadOnly libraryItem, Loadout.ReadOnly targetLoadout);
}
diff --git a/src/Abstractions/NexusMods.Abstractions.Library/NexusMods.Abstractions.Library.csproj b/src/Abstractions/NexusMods.Abstractions.Library/NexusMods.Abstractions.Library.csproj
index c838fae56b..5301250070 100644
--- a/src/Abstractions/NexusMods.Abstractions.Library/NexusMods.Abstractions.Library.csproj
+++ b/src/Abstractions/NexusMods.Abstractions.Library/NexusMods.Abstractions.Library.csproj
@@ -4,22 +4,8 @@
-
-
-
-
-
+
+
-
-
- LibraryItem.cs
-
-
- LibraryItem.cs
-
-
- LibraryArchive.cs
-
-
diff --git a/src/Abstractions/NexusMods.Abstractions.Loadouts/LibraryLinkedLoadoutItem.cs b/src/Abstractions/NexusMods.Abstractions.Loadouts/LibraryLinkedLoadoutItem.cs
index fcef28fb93..a964f3a865 100644
--- a/src/Abstractions/NexusMods.Abstractions.Loadouts/LibraryLinkedLoadoutItem.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Loadouts/LibraryLinkedLoadoutItem.cs
@@ -1,5 +1,5 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
diff --git a/src/Abstractions/NexusMods.Abstractions.Loadouts/LoadoutItem.cs b/src/Abstractions/NexusMods.Abstractions.Loadouts/LoadoutItem.cs
index c0a48596b9..edae3d3433 100644
--- a/src/Abstractions/NexusMods.Abstractions.Loadouts/LoadoutItem.cs
+++ b/src/Abstractions/NexusMods.Abstractions.Loadouts/LoadoutItem.cs
@@ -1,5 +1,5 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
@@ -37,9 +37,4 @@ public partial class LoadoutItem : IModelDefinition
/// Optional parent of the item.
///
public static readonly ReferenceAttribute Parent = new(Namespace, nameof(Parent)) { IsIndexed = true, IsOptional = true };
-
- ///
- /// Optional source of the item.
- ///
- public static readonly ReferenceAttribute Source = new(Namespace, nameof(Source)) { IsIndexed = true, IsOptional = true };
}
diff --git a/src/Abstractions/NexusMods.Abstractions.Loadouts/NexusMods.Abstractions.Loadouts.csproj b/src/Abstractions/NexusMods.Abstractions.Loadouts/NexusMods.Abstractions.Loadouts.csproj
index 6fa6ed2177..c519166dcc 100644
--- a/src/Abstractions/NexusMods.Abstractions.Loadouts/NexusMods.Abstractions.Loadouts.csproj
+++ b/src/Abstractions/NexusMods.Abstractions.Loadouts/NexusMods.Abstractions.Loadouts.csproj
@@ -7,7 +7,7 @@
-
+
all
diff --git a/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusMods.Abstractions.NexusModsLibrary.csproj b/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusMods.Abstractions.NexusModsLibrary.csproj
index 7fca010760..e7df41743e 100644
--- a/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusMods.Abstractions.NexusModsLibrary.csproj
+++ b/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusMods.Abstractions.NexusModsLibrary.csproj
@@ -3,7 +3,7 @@
-
+
diff --git a/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusModsLibraryFile.cs b/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusModsLibraryFile.cs
index 27e321daa1..cd50405b3d 100644
--- a/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusModsLibraryFile.cs
+++ b/src/Abstractions/NexusMods.Abstractions.NexusModsLibrary/NexusModsLibraryFile.cs
@@ -1,5 +1,5 @@
using JetBrains.Annotations;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
diff --git a/src/NexusMods.App/NexusMods.App.csproj b/src/NexusMods.App/NexusMods.App.csproj
index 7ea30baad5..f2fd49fab9 100644
--- a/src/NexusMods.App/NexusMods.App.csproj
+++ b/src/NexusMods.App/NexusMods.App.csproj
@@ -24,6 +24,8 @@
+
+
diff --git a/src/NexusMods.App/Services.cs b/src/NexusMods.App/Services.cs
index 3260c7260e..a32599e5db 100644
--- a/src/NexusMods.App/Services.cs
+++ b/src/NexusMods.App/Services.cs
@@ -3,6 +3,7 @@
using NexusMods.Abstractions.FileStore;
using NexusMods.Abstractions.Games;
using NexusMods.Abstractions.Installers;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.Abstractions.Serialization;
using NexusMods.Abstractions.Settings;
@@ -21,6 +22,8 @@
using NexusMods.Games.Generic;
using NexusMods.Games.Reshade;
using NexusMods.Games.TestHarness;
+using NexusMods.Jobs;
+using NexusMods.Library;
using NexusMods.Networking.Downloaders;
using NexusMods.Networking.HttpDownloader;
using NexusMods.Networking.NexusWebApi;
@@ -56,6 +59,10 @@ public static IServiceCollection AddApp(this IServiceCollection services,
{
services
.AddDataModel()
+ .AddLibrary()
+ .AddLibraryModels()
+ .AddJobMonitor()
+
.AddSettings()
.AddSettings()
.AddSettings()
diff --git a/src/NexusMods.DataModel/ArchiveInstaller.cs b/src/NexusMods.DataModel/ArchiveInstaller.cs
index 5f725109c0..9cd7e3b1c4 100644
--- a/src/NexusMods.DataModel/ArchiveInstaller.cs
+++ b/src/NexusMods.DataModel/ArchiveInstaller.cs
@@ -2,17 +2,19 @@
using Microsoft.Extensions.Logging;
using NexusMods.Abstractions.Activities;
using NexusMods.Abstractions.FileStore;
-using NexusMods.Abstractions.FileStore.ArchiveMetadata;
using NexusMods.Abstractions.FileStore.Downloads;
using NexusMods.Abstractions.Games;
using NexusMods.Abstractions.Installers;
using NexusMods.Abstractions.IO;
+using NexusMods.Abstractions.Library;
using NexusMods.Abstractions.Loadouts;
-using NexusMods.Abstractions.Loadouts.Ids;
using NexusMods.Abstractions.Loadouts.Mods;
+using NexusMods.App.BuildInfo;
using NexusMods.Extensions.BCL;
+using NexusMods.Hashing.xxHash64;
using NexusMods.MnemonicDB.Abstractions;
using File = NexusMods.Abstractions.Loadouts.Files.File;
+using LibraryFile = NexusMods.Abstractions.Library.Models.LibraryFile;
namespace NexusMods.DataModel;
@@ -22,6 +24,7 @@ namespace NexusMods.DataModel;
public class ArchiveInstaller : IArchiveInstaller
{
private readonly ILogger _logger;
+ private readonly ILibraryService _libraryService;
private readonly IConnection _conn;
private readonly IActivityFactory _activityFactory;
private readonly IFileStore _fileStore;
@@ -31,7 +34,9 @@ public class ArchiveInstaller : IArchiveInstaller
///
/// DI Constructor
///
- public ArchiveInstaller(ILogger logger,
+ public ArchiveInstaller(
+ ILogger logger,
+ ILibraryService libraryService,
IFileOriginRegistry fileOriginRegistry,
IConnection conn,
IFileStore fileStore,
@@ -39,13 +44,37 @@ public ArchiveInstaller(ILogger logger,
IServiceProvider provider)
{
_logger = logger;
+ _libraryService = libraryService;
_conn = conn;
_fileOriginRegistry = fileOriginRegistry;
_fileStore = fileStore;
_activityFactory = activityFactory;
_provider = provider;
}
-
+
+ private async Task ShadowTrafficTestLibraryService(Hash hash, Loadout.ReadOnly loadout, CancellationToken cancellationToken)
+ {
+ // TODO: https://github.com/Nexus-Mods/NexusMods.App/issues/1763
+ if (!CompileConstants.IsDebug) return;
+ try
+ {
+ if (!LibraryFile.FindByHash(_conn.Db, hash).TryGetFirst(out var libraryFile))
+ {
+ _logger.LogDebug("Found no library item with hash `{Hash}`, skipping shadow traffic test", hash);
+ return;
+ }
+
+ var job = _libraryService.InstallItem(libraryFile.AsLibraryItem(), loadout);
+ await job.StartAsync(cancellationToken: cancellationToken);
+ var result = await job.WaitToFinishAsync(cancellationToken: cancellationToken);
+ _logger.LogInformation("InstallItem result: `{Result}`", result.ToString());
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Exception install library item");
+ }
+ }
+
///
public async Task AddMods(
LoadoutId loadoutId,
@@ -57,7 +86,9 @@ public async Task AddMods(
// Get the loadout and create the mod, so we can use it in the job.
var useCustomInstaller = installer != null;
var loadout = Loadout.Load(_conn.Db, loadoutId);
-
+
+ await ShadowTrafficTestLibraryService(download.Hash, loadout, token);
+
// Note(suggestedName) cannot be null here.
// Because string is non-nullable where it is set (FileOriginRegistry),
// and using that is a prerequisite to calling this function.
diff --git a/src/NexusMods.DataModel/FileOriginRegistry.cs b/src/NexusMods.DataModel/FileOriginRegistry.cs
index da92fb3dfc..10d99442a4 100644
--- a/src/NexusMods.DataModel/FileOriginRegistry.cs
+++ b/src/NexusMods.DataModel/FileOriginRegistry.cs
@@ -1,4 +1,5 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using NexusMods.Abstractions.DiskState;
using NexusMods.Abstractions.FileExtractor;
@@ -7,6 +8,8 @@
using NexusMods.Abstractions.FileStore.Downloads;
using NexusMods.Abstractions.IO;
using NexusMods.Abstractions.IO.StreamFactories;
+using NexusMods.Abstractions.Library;
+using NexusMods.App.BuildInfo;
using NexusMods.Extensions.Hashing;
using NexusMods.Hashing.xxHash64;
using NexusMods.MnemonicDB.Abstractions;
@@ -23,6 +26,7 @@ namespace NexusMods.DataModel;
public class FileOriginRegistry : IFileOriginRegistry
{
private readonly ILogger _logger;
+ private readonly ILibraryService _libraryService;
private readonly IFileExtractor _extractor;
private readonly IFileStore _fileStore;
private readonly TemporaryFileManager _temporaryFileManager;
@@ -30,17 +34,19 @@ public class FileOriginRegistry : IFileOriginRegistry
private readonly IFileHashCache _fileHashCache;
///
- /// DI Constructor
+ /// Constructor.
///
- ///
- ///
- ///
- ///
- ///
- public FileOriginRegistry(ILogger logger, IFileExtractor extractor,
- IFileStore fileStore, TemporaryFileManager temporaryFileManager, IConnection conn, IFileHashCache fileHashCache)
+ public FileOriginRegistry(
+ ILogger logger,
+ ILibraryService library,
+ IFileExtractor extractor,
+ IFileStore fileStore,
+ TemporaryFileManager temporaryFileManager,
+ IConnection conn,
+ IFileHashCache fileHashCache)
{
_logger = logger;
+ _libraryService = library;
_extractor = extractor;
_fileStore = fileStore;
_temporaryFileManager = temporaryFileManager;
@@ -72,9 +78,28 @@ void AppendNestedArchiveMetadata(ITransaction tx, EntityId id)
}
}
+ private async Task ShadowTrafficTestLibraryService(AbsolutePath path, CancellationToken cancellationToken)
+ {
+ // TODO: https://github.com/Nexus-Mods/NexusMods.App/issues/1763
+ if (!CompileConstants.IsDebug) return;
+ try
+ {
+ var job = _libraryService.AddLocalFile(path);
+ await job.StartAsync(cancellationToken: cancellationToken);
+ var result = await job.WaitToFinishAsync(cancellationToken: cancellationToken);
+ _logger.LogInformation("AddLocalFile result: `{Result}`", result.ToString());
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Exception adding local file to library");
+ }
+ }
+
///
public async ValueTask RegisterDownload(AbsolutePath path, MetadataFn metaDataFn, string modName, CancellationToken token = default)
{
+ await ShadowTrafficTestLibraryService(path, token);
+
var db = _conn.Db;
var archiveSize = (ulong) path.FileInfo.Size;
var archiveHash = (await _fileHashCache.IndexFileAsync(path, token)).Hash;
@@ -88,8 +113,11 @@ public async ValueTask RegisterDownload(AbsolutePath path, MetadataF
return await RegisterFolderInternal(tmpFolder.Path, metaDataFn, null, _fileStore.GetFileHashes(), archiveHash.Value, archiveSize, modName, token);
}
+ ///
public async ValueTask RegisterDownload(AbsolutePath path, EntityId id, string modName, CancellationToken token = default)
{
+ await ShadowTrafficTestLibraryService(path, token);
+
var db = _conn.Db;
var archiveSize = (ulong) path.FileInfo.Size;
diff --git a/src/NexusMods.DataModel/NexusMods.DataModel.csproj b/src/NexusMods.DataModel/NexusMods.DataModel.csproj
index da8ec57fb4..f6bd200d22 100644
--- a/src/NexusMods.DataModel/NexusMods.DataModel.csproj
+++ b/src/NexusMods.DataModel/NexusMods.DataModel.csproj
@@ -4,6 +4,7 @@
+
diff --git a/src/NexusMods.Jobs/JobMonitor.cs b/src/NexusMods.Jobs/JobMonitor.cs
new file mode 100644
index 0000000000..21a624f12d
--- /dev/null
+++ b/src/NexusMods.Jobs/JobMonitor.cs
@@ -0,0 +1,43 @@
+using System.Collections.ObjectModel;
+using System.Reactive.Disposables;
+using DynamicData;
+using JetBrains.Annotations;
+using NexusMods.Abstractions.Jobs;
+
+namespace NexusMods.Jobs;
+
+[UsedImplicitly]
+public sealed class JobMonitor : IJobMonitor, IDisposable
+{
+ private readonly SourceCache _jobSourceCache = new(job => job.Id);
+ private readonly ReadOnlyObservableCollection _jobs;
+ public ReadOnlyObservableCollection Jobs => _jobs;
+
+ private readonly CompositeDisposable _compositeDisposable = new();
+
+ public JobMonitor()
+ {
+ var disposable = _jobSourceCache
+ .Connect()
+ .Bind(out _jobs)
+ .Subscribe();
+
+ _compositeDisposable.Add(disposable);
+ }
+
+ public IObservable> GetObservableChangeSet() where TJob : IJob
+ {
+ return _jobSourceCache.Connect().OfType();
+ }
+
+ public void RegisterJob(IJob job)
+ {
+ _jobSourceCache.AddOrUpdate(job);
+ }
+
+ public void Dispose()
+ {
+ _compositeDisposable.Dispose();
+ _jobSourceCache.Dispose();
+ }
+}
diff --git a/src/NexusMods.Jobs/NexusMods.Jobs.csproj b/src/NexusMods.Jobs/NexusMods.Jobs.csproj
new file mode 100644
index 0000000000..d341e0f871
--- /dev/null
+++ b/src/NexusMods.Jobs/NexusMods.Jobs.csproj
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/NexusMods.Jobs/Services.cs b/src/NexusMods.Jobs/Services.cs
new file mode 100644
index 0000000000..e6c1d012bf
--- /dev/null
+++ b/src/NexusMods.Jobs/Services.cs
@@ -0,0 +1,12 @@
+using Microsoft.Extensions.DependencyInjection;
+using NexusMods.Abstractions.Jobs;
+
+namespace NexusMods.Jobs;
+
+public static class Services
+{
+ public static IServiceCollection AddJobMonitor(this IServiceCollection serviceCollection)
+ {
+ return serviceCollection.AddSingleton();
+ }
+}
diff --git a/src/NexusMods.Library/AddLibraryFileJob.cs b/src/NexusMods.Library/AddLibraryFileJob.cs
index 658245ca14..a1ba63400e 100644
--- a/src/NexusMods.Library/AddLibraryFileJob.cs
+++ b/src/NexusMods.Library/AddLibraryFileJob.cs
@@ -1,6 +1,6 @@
using DynamicData.Kernel;
using NexusMods.Abstractions.Jobs;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.Paths;
@@ -14,15 +14,17 @@ public AddLibraryFileJob(IJobGroup? group = null, IJobWorker? worker = null)
public required ITransaction Transaction { get; init; }
public required AbsolutePath FilePath { get; init; }
public required bool DoCommit { get; init; }
+ public required bool DoBackup { get; init; }
public Optional EntityId { get; set; }
public Optional IsArchive { get; set; }
+ public Optional HasBackup { get; set; }
public Optional HashJobResult { get; set; }
public Optional LibraryFile { get; set; }
public Optional LibraryArchive { get; set; }
public Optional ExtractionDirectory { get; set; }
public Optional ExtractedFiles { get; set; }
- public Optional AddExtractedFileJobResults { get; set; }
+ public Optional[]> AddExtractedFileJobResults { get; set; }
protected override void Dispose(bool disposing)
{
diff --git a/src/NexusMods.Library/AddLibraryFileJobWorker.cs b/src/NexusMods.Library/AddLibraryFileJobWorker.cs
index a7c98227d3..d82fff64c3 100644
--- a/src/NexusMods.Library/AddLibraryFileJobWorker.cs
+++ b/src/NexusMods.Library/AddLibraryFileJobWorker.cs
@@ -2,9 +2,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NexusMods.Abstractions.FileExtractor;
+using NexusMods.Abstractions.IO;
using NexusMods.Abstractions.IO.StreamFactories;
using NexusMods.Abstractions.Jobs;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Hashing.xxHash64;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.Paths;
@@ -19,6 +20,7 @@ internal class AddLibraryFileJobWorker : AJobWorker
private readonly IServiceProvider _serviceProvider;
private readonly IFileExtractor _fileExtractor;
private readonly TemporaryFileManager _temporaryFileManager;
+ private readonly IFileStore _fileStore;
public AddLibraryFileJobWorker(IServiceProvider serviceProvider)
{
@@ -27,6 +29,7 @@ public AddLibraryFileJobWorker(IServiceProvider serviceProvider)
_serviceProvider = serviceProvider;
_fileExtractor = serviceProvider.GetRequiredService();
_temporaryFileManager = serviceProvider.GetRequiredService();
+ _fileStore = serviceProvider.GetRequiredService();
}
protected override async Task ExecuteAsync(AddLibraryFileJob job, CancellationToken cancellationToken)
@@ -103,28 +106,56 @@ protected override async Task ExecuteAsync(AddLibraryFileJob job, Can
if (!job.AddExtractedFileJobResults.HasValue)
{
var extractedFiles = job.ExtractedFiles.Value;
- var results = new JobResult[extractedFiles.Length];
+ var results = new ValueTuple[extractedFiles.Length];
await Parallel.ForAsync(fromInclusive: 0, toExclusive: extractedFiles.Length, cancellationToken, async (i, innerCancellationToken) =>
{
+ var fileEntry = extractedFiles[i];
+
var worker = _serviceProvider.GetRequiredService();
var childJob = new AddLibraryFileJob(job, worker)
{
Transaction = job.Transaction,
- FilePath = extractedFiles[i].Path,
+ FilePath = fileEntry.Path,
DoCommit = false,
+ DoBackup = false,
};
await worker.StartAsync(childJob, cancellationToken: innerCancellationToken);
var result = await childJob.WaitToFinishAsync(cancellationToken: innerCancellationToken);
- results[i] = result;
+ results[i] = (result, fileEntry);
});
+
+ job.AddExtractedFileJobResults = results;
+ }
+
+ cancellationToken.ThrowIfCancellationRequested();
+ if (!job.HasBackup.HasValue)
+ {
+ var filesToBackup = job.AddExtractedFileJobResults.Value
+ .Select(tuple =>
+ {
+ var (jobResult, fileEntry) = tuple;
+ var data = jobResult.RequireData();
+
+ return new ArchivedFileEntry
+ {
+ Hash = data.Hash,
+ Size = data.Size,
+ StreamFactory = new NativeFileStreamFactory(fileEntry.Path),
+ };
+ })
+ .ToArray();
+
+ await _fileStore.BackupFiles(filesToBackup, token: cancellationToken);
+ job.HasBackup = true;
}
cancellationToken.ThrowIfCancellationRequested();
- foreach (var jobResult in job.AddExtractedFileJobResults.Value)
+ foreach (var tuple in job.AddExtractedFileJobResults.Value)
{
+ var (jobResult, _) = tuple;
var libraryFile = jobResult.RequireData();
var archiveFileEntry = new LibraryArchiveFileEntry.New(job.Transaction, libraryFile.Id)
{
@@ -133,6 +164,22 @@ await Parallel.ForAsync(fromInclusive: 0, toExclusive: extractedFiles.Length, ca
};
}
}
+ else
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ if (job is { DoBackup: true, HasBackup.HasValue: false })
+ {
+ var archivedFileEntry = new ArchivedFileEntry
+ {
+ Hash = job.HashJobResult.Value.RequireData(),
+ Size = job.FilePath.FileInfo.Size,
+ StreamFactory = new NativeFileStreamFactory(job.FilePath),
+ };
+
+ await _fileStore.BackupFiles([archivedFileEntry], token: cancellationToken);
+ job.HasBackup = true;
+ }
+ }
cancellationToken.ThrowIfCancellationRequested();
if (job.DoCommit)
diff --git a/src/NexusMods.Library/AddLocalFileJobWorker.cs b/src/NexusMods.Library/AddLocalFileJobWorker.cs
index e5304cabd0..39a5b2dd38 100644
--- a/src/NexusMods.Library/AddLocalFileJobWorker.cs
+++ b/src/NexusMods.Library/AddLocalFileJobWorker.cs
@@ -1,7 +1,7 @@
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using NexusMods.Abstractions.Jobs;
-using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
namespace NexusMods.Library;
@@ -25,6 +25,7 @@ protected override async Task ExecuteAsync(AddLocalFileJob job, Cance
Transaction = job.Transaction,
FilePath = job.FilePath,
DoCommit = false,
+ DoBackup = true,
};
await worker.StartAsync(addLibraryFileJob, cancellationToken: cancellationToken);
diff --git a/src/NexusMods.Library/InstallLoadoutItemJob.cs b/src/NexusMods.Library/InstallLoadoutItemJob.cs
new file mode 100644
index 0000000000..d1de69bd56
--- /dev/null
+++ b/src/NexusMods.Library/InstallLoadoutItemJob.cs
@@ -0,0 +1,32 @@
+using DynamicData.Kernel;
+using NexusMods.Abstractions.Jobs;
+using NexusMods.Abstractions.Library.Installers;
+using NexusMods.Abstractions.Library.Models;
+using NexusMods.Abstractions.Loadouts;
+using NexusMods.MnemonicDB.Abstractions;
+
+namespace NexusMods.Library;
+
+public class InstallLoadoutItemJob : AJob
+{
+ public InstallLoadoutItemJob(
+ IJobGroup? group = default,
+ IJobWorker? worker = default,
+ IJobMonitor? monitor = default) : base(new MutableProgress(new IndeterminateProgress()), group, worker, monitor) { }
+
+ public required ITransaction Transaction { get; init; }
+ public required LibraryItem.ReadOnly LibraryItem { get; init; }
+ public required Loadout.ReadOnly Loadout { get; init; }
+
+ public Optional Installer { get; set; }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Transaction.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+}
diff --git a/src/NexusMods.Library/InstallLoadoutItemJobWorker.cs b/src/NexusMods.Library/InstallLoadoutItemJobWorker.cs
new file mode 100644
index 0000000000..1d5f48635c
--- /dev/null
+++ b/src/NexusMods.Library/InstallLoadoutItemJobWorker.cs
@@ -0,0 +1,54 @@
+using DynamicData.Kernel;
+using JetBrains.Annotations;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using NexusMods.Abstractions.Games;
+using NexusMods.Abstractions.Installers;
+using NexusMods.Abstractions.Jobs;
+using NexusMods.Abstractions.Library.Installers;
+using NexusMods.Abstractions.Loadouts;
+
+namespace NexusMods.Library;
+
+[UsedImplicitly]
+internal class InstallLoadoutItemJobWorker : AJobWorker
+{
+ private readonly ILogger _logger;
+
+ public InstallLoadoutItemJobWorker(IServiceProvider serviceProvider)
+ {
+ _logger = serviceProvider.GetRequiredService>();
+ }
+
+ protected override async Task ExecuteAsync(InstallLoadoutItemJob job, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ if (!job.Installer.HasValue)
+ {
+ ILibraryItemInstaller? foundInstaller = null;
+ var installers = job.Loadout.InstallationInstance.GetGame().LibraryItemInstallers;
+ foreach (var installer in installers)
+ {
+ var isSupported = await installer.IsSupportedAsync(job.LibraryItem, cancellationToken);
+ if (!isSupported) continue;
+
+ foundInstaller = installer;
+ break;
+ }
+
+ // TODO: default to advanced installer
+ if (foundInstaller is null)
+ {
+ return JobResult.CreateFailed($"Found no installer that supports `{job.LibraryItem.Name}` (`{job.LibraryItem.Id}`)");
+ }
+
+ job.Installer = Optional.Create(foundInstaller);
+ }
+
+ var result = await job.Installer.Value.ExecuteAsync(job.LibraryItem, job.Transaction, job.Loadout, cancellationToken);
+ var transactionResult = await job.Transaction.Commit();
+
+ var jobResults = result.Select(x => transactionResult.Remap(x)).ToArray();
+ return JobResult.CreateCompleted(jobResults);
+ }
+}
diff --git a/src/NexusMods.Library/LibraryService.cs b/src/NexusMods.Library/LibraryService.cs
index 4734ecb011..a136d393d5 100644
--- a/src/NexusMods.Library/LibraryService.cs
+++ b/src/NexusMods.Library/LibraryService.cs
@@ -1,7 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using NexusMods.Abstractions.Downloads;
using NexusMods.Abstractions.Jobs;
using NexusMods.Abstractions.Library;
+using NexusMods.Abstractions.Library.Models;
+using NexusMods.Abstractions.Loadouts;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.Paths;
@@ -26,6 +29,11 @@ public LibraryService(ILogger logger, IConnection connection, IS
_serviceProvider = serviceProvider;
}
+ public IJob AddDownload(IDownloadJob downloadJob)
+ {
+ throw new NotImplementedException();
+ }
+
public IJob AddLocalFile(AbsolutePath absolutePath)
{
var group = new AddLocalFileJob(worker: _serviceProvider.GetRequiredService())
@@ -36,4 +44,16 @@ public IJob AddLocalFile(AbsolutePath absolutePath)
return group;
}
+
+ public IJob InstallItem(LibraryItem.ReadOnly libraryItem, Loadout.ReadOnly targetLoadout)
+ {
+ var job = new InstallLoadoutItemJob(worker: _serviceProvider.GetRequiredService())
+ {
+ Transaction = _connection.BeginTransaction(),
+ LibraryItem = libraryItem,
+ Loadout = targetLoadout,
+ };
+
+ return job;
+ }
}
diff --git a/src/NexusMods.Library/NexusMods.Library.csproj b/src/NexusMods.Library/NexusMods.Library.csproj
index f141f3c01f..942fb20815 100644
--- a/src/NexusMods.Library/NexusMods.Library.csproj
+++ b/src/NexusMods.Library/NexusMods.Library.csproj
@@ -2,7 +2,10 @@
+
+
+
diff --git a/src/NexusMods.Library/Services.cs b/src/NexusMods.Library/Services.cs
index a1c343062b..b1188e3a44 100644
--- a/src/NexusMods.Library/Services.cs
+++ b/src/NexusMods.Library/Services.cs
@@ -15,6 +15,11 @@ public static class Services
///
public static IServiceCollection AddLibrary(this IServiceCollection serviceCollection)
{
- return serviceCollection.AddSingleton();
+ return serviceCollection
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton();
}
}
diff --git a/src/NexusMods.StandardGameLocators/Unknown/UnknownGame.cs b/src/NexusMods.StandardGameLocators/Unknown/UnknownGame.cs
index b07f941a0e..b77d96f656 100644
--- a/src/NexusMods.StandardGameLocators/Unknown/UnknownGame.cs
+++ b/src/NexusMods.StandardGameLocators/Unknown/UnknownGame.cs
@@ -4,6 +4,7 @@
using NexusMods.Abstractions.Games.DTO;
using NexusMods.Abstractions.Installers;
using NexusMods.Abstractions.IO;
+using NexusMods.Abstractions.Library.Installers;
using NexusMods.Abstractions.Loadouts.Mods;
using NexusMods.Abstractions.Loadouts.Synchronizers;
using NexusMods.Abstractions.Serialization;
@@ -60,6 +61,9 @@ public void ResetInstallations() { }
///
public ILoadoutSynchronizer Synchronizer => throw new NotImplementedException();
+ ///
+ public ILibraryItemInstaller[] LibraryItemInstallers { get; } = [];
+
///
public GameInstallation InstallationFromLocatorResult(GameLocatorResult metadata, EntityId dbId, IGameLocator locator)
{
diff --git a/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs b/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs
index a63a7064c3..a696adfbd5 100644
--- a/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs
+++ b/tests/Games/NexusMods.Games.TestFramework/DependencyInjectionHelper.cs
@@ -2,14 +2,16 @@
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using NexusMods.Abstractions.Activities;
using NexusMods.Abstractions.HttpDownloader;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts.Synchronizers;
using NexusMods.Abstractions.Settings;
using NexusMods.Activities;
using NexusMods.CrossPlatform;
using NexusMods.DataModel;
using NexusMods.FileExtractor;
+using NexusMods.Jobs;
+using NexusMods.Library;
using NexusMods.Networking.HttpDownloader;
using NexusMods.Networking.NexusWebApi;
using NexusMods.Paths;
@@ -59,6 +61,9 @@ public static IServiceCollection AddDefaultServicesForTesting(this IServiceColle
.AddSettings()
.AddHttpDownloader()
.AddDataModel()
+ .AddLibrary()
+ .AddLibraryModels()
+ .AddJobMonitor()
.AddLoadoutsSynchronizers()
.OverrideSettingsForTests(settings => settings with
{
diff --git a/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj b/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj
index c3b104b69a..83688aa1a7 100644
--- a/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj
+++ b/tests/Games/NexusMods.Games.TestFramework/NexusMods.Games.TestFramework.csproj
@@ -5,6 +5,8 @@
+
+
diff --git a/tests/NexusMods.CLI.Tests/Startup.cs b/tests/NexusMods.CLI.Tests/Startup.cs
index 297729ccd0..759f224da8 100644
--- a/tests/NexusMods.CLI.Tests/Startup.cs
+++ b/tests/NexusMods.CLI.Tests/Startup.cs
@@ -3,6 +3,7 @@
using NexusMods.Abstractions.FileStore;
using NexusMods.Abstractions.Games;
using NexusMods.Abstractions.Installers;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.Abstractions.Serialization;
using NexusMods.Abstractions.Settings;
@@ -11,6 +12,8 @@
using NexusMods.CrossPlatform;
using NexusMods.DataModel;
using NexusMods.FileExtractor;
+using NexusMods.Jobs;
+using NexusMods.Library;
using NexusMods.Networking.HttpDownloader;
using NexusMods.Networking.HttpDownloader.Tests;
using NexusMods.Networking.NexusWebApi;
@@ -33,6 +36,9 @@ public void ConfigureServices(IServiceCollection services)
.AddFileSystem()
.AddSettingsManager()
.AddDataModel()
+ .AddLibrary()
+ .AddLibraryModels()
+ .AddJobMonitor()
.OverrideSettingsForTests(settings => settings with
{
UseInMemoryDataModel = true,
diff --git a/tests/NexusMods.DataModel.Tests/FileOriginRegistryTests.cs b/tests/NexusMods.DataModel.Tests/FileOriginRegistryTests.cs
index f5945fefd9..65cc13e551 100644
--- a/tests/NexusMods.DataModel.Tests/FileOriginRegistryTests.cs
+++ b/tests/NexusMods.DataModel.Tests/FileOriginRegistryTests.cs
@@ -6,6 +6,7 @@
using NexusMods.Abstractions.FileExtractor;
using NexusMods.Abstractions.FileStore;
using NexusMods.Abstractions.IO;
+using NexusMods.Abstractions.Library;
using NexusMods.DataModel.Tests.Harness;
using NexusMods.Hashing.xxHash64;
using NSubstitute;
@@ -21,6 +22,7 @@ public async Task RegisterFolder_ShouldRegisterCorrectly()
// Arrange
IFileOriginRegistry sut = new FileOriginRegistry(
ServiceProvider.GetRequiredService>(),
+ ServiceProvider.GetRequiredService(),
ServiceProvider.GetRequiredService(),
FileStore,
TemporaryFileManager,
@@ -52,6 +54,7 @@ public async Task RegisterFolder_WhenCalledTwice_ShouldBeDedupedOnSameArchive()
fileStore.GetFileHashes().Returns(new HashSet()); // not needed here
IFileOriginRegistry sut = new FileOriginRegistry(
ServiceProvider.GetRequiredService>(),
+ ServiceProvider.GetRequiredService(),
ServiceProvider.GetRequiredService(),
fileStore,
TemporaryFileManager,
@@ -78,6 +81,7 @@ public async Task RegisterFolder_WhenCalledTwice_ShouldOnlyAppendNewData()
IFileOriginRegistry sut = new FileOriginRegistry(
ServiceProvider.GetRequiredService>(),
+ ServiceProvider.GetRequiredService(),
ServiceProvider.GetRequiredService(),
fileStore,
TemporaryFileManager,
diff --git a/tests/NexusMods.DataModel.Tests/NexusMods.DataModel.Tests.csproj b/tests/NexusMods.DataModel.Tests/NexusMods.DataModel.Tests.csproj
index 31c6b97ac7..70be2a13cd 100644
--- a/tests/NexusMods.DataModel.Tests/NexusMods.DataModel.Tests.csproj
+++ b/tests/NexusMods.DataModel.Tests/NexusMods.DataModel.Tests.csproj
@@ -10,6 +10,8 @@
+
+
diff --git a/tests/NexusMods.DataModel.Tests/Startup.cs b/tests/NexusMods.DataModel.Tests/Startup.cs
index 83b750799f..60c984cf42 100644
--- a/tests/NexusMods.DataModel.Tests/Startup.cs
+++ b/tests/NexusMods.DataModel.Tests/Startup.cs
@@ -4,6 +4,7 @@
using NexusMods.Abstractions.Games;
using NexusMods.Abstractions.GuidedInstallers;
using NexusMods.Abstractions.Installers;
+using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.Loadouts;
using NexusMods.Abstractions.Serialization;
using NexusMods.Abstractions.Serialization.ExpressionGenerator;
@@ -12,6 +13,8 @@
using NexusMods.App.BuildInfo;
using NexusMods.CrossPlatform;
using NexusMods.FileExtractor;
+using NexusMods.Jobs;
+using NexusMods.Library;
using NexusMods.Paths;
using NexusMods.Settings;
using NexusMods.StandardGameLocators;
@@ -49,6 +52,9 @@ public static IServiceCollection AddServices(IServiceCollection container)
.AddSingleton(new TemporaryFileManager(FileSystem.Shared, prefix))
.AddSettingsManager()
.AddDataModel()
+ .AddLibrary()
+ .AddLibraryModels()
+ .AddJobMonitor()
.OverrideSettingsForTests(settings => settings with
{
UseInMemoryDataModel = true,
diff --git a/tests/NexusMods.Jobs.Tests/JobWorkerTests.cs b/tests/NexusMods.Jobs.Tests/JobWorkerTests.cs
index f6106d798d..4bd8cf60ff 100644
--- a/tests/NexusMods.Jobs.Tests/JobWorkerTests.cs
+++ b/tests/NexusMods.Jobs.Tests/JobWorkerTests.cs
@@ -10,7 +10,7 @@ public class JobWorkerTests
public async Task TestCreateSync()
{
var job = new MyJob();
- var worker = JobWorker.Create(new MyJob(), (_, _, _) => Task.FromResult("hello world"));
+ var worker = JobWorker.CreateWithData(new MyJob(), (_, _, _) => Task.FromResult("hello world"));
await worker.StartAsync(job);
var jobResult = await job.WaitToFinishAsync();
@@ -23,7 +23,7 @@ public async Task TestCreateSync()
public async Task TestCreateAsync()
{
var job = new MyJob();
- var worker = JobWorker.Create(new MyJob(), async (_, _, _) =>
+ var worker = JobWorker.CreateWithData(new MyJob(), async (_, _, _) =>
{
await Task.Yield();
return "hello world";