2021-09-27 12:42:46 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2022-06-08 03:48:13 +00:00
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Linq;
|
2021-09-27 12:42:46 +00:00
|
|
|
using System.Net.Http;
|
2021-10-23 16:51:17 +00:00
|
|
|
using System.Runtime.InteropServices;
|
2021-09-27 12:42:46 +00:00
|
|
|
using System.Threading.Tasks;
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2022-06-22 02:57:26 +00:00
|
|
|
using Microsoft.Extensions.Logging;
|
2021-11-10 23:13:02 +00:00
|
|
|
using Wabbajack.App.Models;
|
2021-09-27 12:42:46 +00:00
|
|
|
using Wabbajack.Compiler;
|
|
|
|
using Wabbajack.Downloaders;
|
2021-10-13 03:59:54 +00:00
|
|
|
using Wabbajack.Downloaders.GameFile;
|
2021-09-27 12:42:46 +00:00
|
|
|
using Wabbajack.DTOs;
|
2022-05-19 03:21:38 +00:00
|
|
|
using Wabbajack.DTOs.Interventions;
|
2021-09-27 12:42:46 +00:00
|
|
|
using Wabbajack.DTOs.Logins;
|
|
|
|
using Wabbajack.Installer;
|
2022-02-10 23:57:44 +00:00
|
|
|
using Wabbajack.Networking.BethesdaNet;
|
2021-09-27 12:42:46 +00:00
|
|
|
using Wabbajack.Networking.Discord;
|
|
|
|
using Wabbajack.Networking.Http;
|
|
|
|
using Wabbajack.Networking.Http.Interfaces;
|
|
|
|
using Wabbajack.Networking.NexusApi;
|
2022-01-08 17:39:23 +00:00
|
|
|
using Wabbajack.Networking.Steam;
|
2022-06-22 02:57:26 +00:00
|
|
|
using Wabbajack.Networking.WabbajackClientApi;
|
2021-09-27 12:42:46 +00:00
|
|
|
using Wabbajack.Paths;
|
|
|
|
using Wabbajack.Paths.IO;
|
|
|
|
using Wabbajack.RateLimiter;
|
2021-12-27 15:37:20 +00:00
|
|
|
using Wabbajack.Services.OSIntegrated.Services;
|
2021-09-27 12:42:46 +00:00
|
|
|
using Wabbajack.Services.OSIntegrated.TokenProviders;
|
|
|
|
using Wabbajack.VFS;
|
2022-06-22 01:38:42 +00:00
|
|
|
using Wabbajack.VFS.Interfaces;
|
2022-01-08 17:39:23 +00:00
|
|
|
using Client = Wabbajack.Networking.WabbajackClientApi.Client;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
namespace Wabbajack.Services.OSIntegrated;
|
|
|
|
|
|
|
|
public static class ServiceExtensions
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Adds variants of services that integrate into global OS services. These are not testing
|
|
|
|
/// variants or services that require Environment variables. These are the "full fat" services.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
public static IServiceCollection AddOSIntegrated(this IServiceCollection service,
|
|
|
|
Action<OSIntegratedOptions>? cfn = null)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
var options = new OSIntegratedOptions();
|
|
|
|
cfn?.Invoke(options);
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2022-06-08 03:48:13 +00:00
|
|
|
var tempBase = KnownFolders.EntryPoint.Combine("temp");
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddTransient(s =>
|
2022-06-08 03:48:13 +00:00
|
|
|
new TemporaryFileManager(tempBase.Combine(Environment.ProcessId + "_" + Guid.NewGuid())));
|
|
|
|
|
|
|
|
Task.Run(() => CleanAllTempData(tempBase));
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
service.AddSingleton(s => options.UseLocalCache
|
|
|
|
? new FileHashCache(s.GetService<TemporaryFileManager>()!.CreateFile().Path,
|
|
|
|
s.GetService<IResource<FileHashCache>>()!)
|
|
|
|
: new FileHashCache(KnownFolders.AppDataLocal.Combine("Wabbajack", "GlobalHashCache.sqlite"),
|
|
|
|
s.GetService<IResource<FileHashCache>>()!));
|
|
|
|
|
2022-06-22 02:57:26 +00:00
|
|
|
service.AddSingleton<IVfsCache>(s =>
|
|
|
|
{
|
|
|
|
var diskCache = options.UseLocalCache
|
|
|
|
? new VFSDiskCache(s.GetService<TemporaryFileManager>()!.CreateFile().Path)
|
2022-07-02 00:01:40 +00:00
|
|
|
: new VFSDiskCache(KnownFolders.WabbajackAppLocal.Combine("GlobalVFSCache3.sqlite"));
|
2022-06-22 02:57:26 +00:00
|
|
|
var cesiCache = new CesiVFSCache(s.GetRequiredService<ILogger<CesiVFSCache>>(),
|
|
|
|
s.GetRequiredService<Client>());
|
|
|
|
return new FallthroughVFSCache(new IVfsCache[] {diskCache, cesiCache});
|
|
|
|
});
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
service.AddSingleton<IBinaryPatchCache>(s => options.UseLocalCache
|
|
|
|
? new BinaryPatchCache(s.GetService<TemporaryFileManager>()!.CreateFile().Path)
|
|
|
|
: new BinaryPatchCache(KnownFolders.EntryPoint.Combine("patchCache.sqlite")));
|
|
|
|
|
|
|
|
service.AddSingleton(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount});
|
2021-11-10 23:13:02 +00:00
|
|
|
|
|
|
|
Func<Task<(int MaxTasks, long MaxThroughput)>> GetSettings(IServiceProvider provider, string name)
|
|
|
|
{
|
|
|
|
return async () =>
|
|
|
|
{
|
|
|
|
var s = await provider.GetService<ResourceSettingsManager>()!.GetSettings(name);
|
|
|
|
return ((int) s.MaxTasks, s.MaxThroughput);
|
|
|
|
};
|
|
|
|
}
|
2021-11-10 23:56:52 +00:00
|
|
|
|
|
|
|
// Settings
|
|
|
|
|
|
|
|
service.AddSingleton(s => new Configuration
|
|
|
|
{
|
|
|
|
EncryptedDataLocation = KnownFolders.WabbajackAppLocal.Combine("encrypted"),
|
|
|
|
ModListsDownloadLocation = KnownFolders.EntryPoint.Combine("downloaded_mod_lists"),
|
|
|
|
SavedSettingsLocation = KnownFolders.WabbajackAppLocal.Combine("saved_settings"),
|
|
|
|
LogLocation = KnownFolders.EntryPoint.Combine("logs"),
|
|
|
|
ImageCacheLocation = KnownFolders.WabbajackAppLocal.Combine("image_cache")
|
|
|
|
});
|
|
|
|
|
|
|
|
service.AddSingleton<SettingsManager>();
|
|
|
|
service.AddSingleton<ResourceSettingsManager>();
|
|
|
|
|
|
|
|
// Resources
|
2021-11-10 23:13:02 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddAllSingleton<IResource, IResource<DownloadDispatcher>>(s =>
|
2021-11-10 23:13:02 +00:00
|
|
|
new Resource<DownloadDispatcher>("Downloads", GetSettings(s, "Downloads")));
|
|
|
|
|
|
|
|
service.AddAllSingleton<IResource, IResource<HttpClient>>(s => new Resource<HttpClient>("Web Requests", GetSettings(s, "Web Requests")));
|
|
|
|
service.AddAllSingleton<IResource, IResource<Context>>(s => new Resource<Context>("VFS", GetSettings(s, "VFS")));
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddAllSingleton<IResource, IResource<FileHashCache>>(s =>
|
2021-11-10 23:13:02 +00:00
|
|
|
new Resource<FileHashCache>("File Hashing", GetSettings(s, "File Hashing")));
|
2022-06-22 01:38:42 +00:00
|
|
|
service.AddAllSingleton<IResource, IResource<Client>>(s =>
|
|
|
|
new Resource<Client>("Wabbajack Client", GetSettings(s, "Wabbajack Client")));
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddAllSingleton<IResource, IResource<FileExtractor.FileExtractor>>(s =>
|
2021-11-10 23:13:02 +00:00
|
|
|
new Resource<FileExtractor.FileExtractor>("File Extractor", GetSettings(s, "File Extractor")));
|
2021-10-23 16:51:17 +00:00
|
|
|
|
2021-10-23 18:36:35 +00:00
|
|
|
service.AddAllSingleton<IResource, IResource<ACompiler>>(s =>
|
2021-11-10 23:13:02 +00:00
|
|
|
new Resource<ACompiler>("Compiler", GetSettings(s, "Compiler")));
|
2022-05-17 05:26:59 +00:00
|
|
|
|
|
|
|
service.AddAllSingleton<IResource, IResource<IInstaller>>(s =>
|
|
|
|
new Resource<IInstaller>("Installer", GetSettings(s, "Installer")));
|
2022-05-19 03:21:38 +00:00
|
|
|
|
|
|
|
service.AddAllSingleton<IResource, IResource<IUserInterventionHandler>>(s =>
|
2022-05-20 04:12:16 +00:00
|
|
|
new Resource<IUserInterventionHandler>("User Intervention", 1));
|
2021-10-23 18:36:35 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddSingleton<LoggingRateLimiterReporter>();
|
|
|
|
|
|
|
|
service.AddScoped<Context>();
|
|
|
|
service.AddSingleton<FileExtractor.FileExtractor>();
|
|
|
|
|
2021-12-27 15:37:20 +00:00
|
|
|
service.AddSingleton<ModListDownloadMaintainer>();
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
// Networking
|
|
|
|
service.AddSingleton<HttpClient>();
|
|
|
|
service.AddAllSingleton<IHttpDownloader, SingleThreadedDownloader>();
|
|
|
|
|
2022-01-08 22:03:39 +00:00
|
|
|
service.AddSteam();
|
2022-01-08 17:39:23 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddSingleton<Client>();
|
|
|
|
service.AddSingleton<WriteOnlyClient>();
|
2022-02-10 23:57:44 +00:00
|
|
|
service.AddBethesdaNet();
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
// Token Providers
|
2022-01-30 05:47:49 +00:00
|
|
|
service.AddAllSingleton<ITokenProvider<NexusApiState>, EncryptedJsonTokenProvider<NexusApiState>, NexusApiTokenProvider>();
|
2022-02-10 23:57:44 +00:00
|
|
|
service.AddAllSingleton<ITokenProvider<BethesdaNetLoginState>, EncryptedJsonTokenProvider<BethesdaNetLoginState>, BethesdaNetTokenProvider>();
|
2021-10-23 16:51:17 +00:00
|
|
|
service
|
|
|
|
.AddAllSingleton<ITokenProvider<LoversLabLoginState>, EncryptedJsonTokenProvider<LoversLabLoginState>,
|
|
|
|
LoversLabTokenProvider>();
|
|
|
|
service
|
|
|
|
.AddAllSingleton<ITokenProvider<VectorPlexusLoginState>, EncryptedJsonTokenProvider<VectorPlexusLoginState>,
|
|
|
|
VectorPlexusTokenProvider>();
|
|
|
|
|
2022-01-08 17:39:23 +00:00
|
|
|
service
|
|
|
|
.AddAllSingleton<ITokenProvider<SteamLoginState>, EncryptedJsonTokenProvider<SteamLoginState>,
|
|
|
|
SteamTokenProvider>();
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddAllSingleton<ITokenProvider<WabbajackApiState>, WabbajackApiTokenProvider>();
|
|
|
|
|
|
|
|
service
|
|
|
|
.AddAllSingleton<ITokenProvider<Dictionary<Channel, DiscordWebHookSetting>>,
|
|
|
|
EncryptedJsonTokenProvider<Dictionary<Channel, DiscordWebHookSetting>>, DiscordTokenProvider>();
|
|
|
|
|
|
|
|
service.AddAllSingleton<NexusApi, ProxiedNexusApi>();
|
|
|
|
service.AddDownloadDispatcher();
|
|
|
|
|
|
|
|
if (options.UseStubbedGameFolders)
|
|
|
|
service.AddAllSingleton<IGameLocator, StubbedGameLocator>();
|
|
|
|
else
|
|
|
|
service.AddAllSingleton<IGameLocator, GameLocator>();
|
|
|
|
|
|
|
|
// Installer/Compiler Configuration
|
|
|
|
service.AddScoped<InstallerConfiguration>();
|
|
|
|
service.AddScoped<StandardInstaller>();
|
2022-05-27 05:41:11 +00:00
|
|
|
service.AddScoped<CompilerSettings>();
|
2021-10-23 16:51:17 +00:00
|
|
|
service.AddScoped<MO2Compiler>();
|
2022-05-25 02:59:15 +00:00
|
|
|
service.AddSingleton<CompilerSettingsInferencer>();
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
// Application Info
|
|
|
|
var version =
|
|
|
|
$"{ThisAssembly.Git.SemVer.Major}.{ThisAssembly.Git.SemVer.Major}.{ThisAssembly.Git.SemVer.Patch}{ThisAssembly.Git.SemVer.DashLabel}";
|
|
|
|
service.AddSingleton(s => new ApplicationInfo
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
ApplicationSlug = "Wabbajack",
|
|
|
|
ApplicationName = Environment.ProcessPath?.ToAbsolutePath().FileName.ToString() ?? "Wabbajack",
|
|
|
|
ApplicationSha = ThisAssembly.Git.Sha,
|
|
|
|
Platform = RuntimeInformation.ProcessArchitecture.ToString(),
|
|
|
|
OperatingSystemDescription = RuntimeInformation.OSDescription,
|
|
|
|
RuntimeIdentifier = RuntimeInformation.RuntimeIdentifier,
|
|
|
|
OSVersion = Environment.OSVersion.VersionString,
|
|
|
|
Version = version
|
|
|
|
});
|
2021-11-10 23:13:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
return service;
|
|
|
|
}
|
|
|
|
|
2022-06-08 03:48:13 +00:00
|
|
|
private static void CleanAllTempData(AbsolutePath path)
|
|
|
|
{
|
|
|
|
// Get directories first and cache them, this freezes the directories were looking at
|
|
|
|
// so any new ones don't show up in the middle of our deletes.
|
|
|
|
|
|
|
|
var dirs = path.EnumerateDirectories().ToList();
|
|
|
|
var processIds = Process.GetProcesses().Select(p => p.Id).ToHashSet();
|
|
|
|
foreach (var dir in dirs)
|
|
|
|
{
|
|
|
|
var name = dir.FileName.ToString().Split("_");
|
|
|
|
if (!int.TryParse(name[0], out var processId)) continue;
|
|
|
|
if (processIds.Contains(processId)) continue;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
dir.DeleteDirectory();
|
|
|
|
}
|
|
|
|
catch (Exception)
|
|
|
|
{
|
|
|
|
// ignored
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public class OSIntegratedOptions
|
|
|
|
{
|
|
|
|
public bool UseLocalCache { get; set; } = false;
|
|
|
|
public bool UseStubbedGameFolders { get; set; } = false;
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
}
|