- Completed most of PackageManagementService.cs
- Some areas of code need to be rewritten for the simplified loading and execution process.
This commit is contained in:
+204
-48
@@ -1,9 +1,12 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.LuaCs.Data;
|
||||
using FluentResults;
|
||||
using Microsoft.Toolkit.Diagnostics;
|
||||
|
||||
namespace Barotrauma.LuaCs.Services;
|
||||
|
||||
@@ -12,20 +15,37 @@ public sealed class PackageManagementService : IPackageManagementService
|
||||
// svc
|
||||
private ILoggerService _logger;
|
||||
private IModConfigService _modConfigService;
|
||||
private IConfigService _configService;
|
||||
private ILuaScriptManagementService _luaScriptManagementService;
|
||||
private IPluginManagementService _pluginManagementService;
|
||||
private IPackageManagementServiceConfig _runConfig;
|
||||
// state
|
||||
private readonly ConcurrentDictionary<ContentPackage, IModConfigInfo> _loadedPackages = new();
|
||||
private readonly ConcurrentDictionary<ContentPackage, IModConfigInfo> _runningPackages = new();
|
||||
// control
|
||||
/// <summary>
|
||||
/// Service Disposal Lock.
|
||||
/// </summary>
|
||||
private readonly AsyncReaderWriterLock _operationsLock = new();
|
||||
/// <summary>
|
||||
/// Execution of packages lock.
|
||||
/// <br/> Read: Package loading/unloading (Multi-operation mode).
|
||||
/// <br/> Write: Package execution (exclusive mode).
|
||||
/// </summary>
|
||||
private readonly AsyncReaderWriterLock _executionLock = new();
|
||||
|
||||
public PackageManagementService(ILoggerService logger, IModConfigService modConfigService, ILuaScriptManagementService luaScriptManagementService, IPluginManagementService pluginManagementService)
|
||||
public PackageManagementService(ILoggerService logger,
|
||||
IModConfigService modConfigService,
|
||||
ILuaScriptManagementService luaScriptManagementService,
|
||||
IPluginManagementService pluginManagementService,
|
||||
IConfigService configService, IPackageManagementServiceConfig runConfig)
|
||||
{
|
||||
_logger = logger;
|
||||
_modConfigService = modConfigService;
|
||||
_luaScriptManagementService = luaScriptManagementService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_configService = configService;
|
||||
_runConfig = runConfig;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -34,7 +54,7 @@ public sealed class PackageManagementService : IPackageManagementService
|
||||
if (!ModUtils.Threading.CheckIfClearAndSetBool(ref _isDisposed))
|
||||
return;
|
||||
|
||||
_logger.LogMessage($"{nameof(PackageManagementService)} is disposing");
|
||||
_logger.LogMessage($"{nameof(PackageManagementService)} is disposing.");
|
||||
_luaScriptManagementService.Dispose();
|
||||
_pluginManagementService.Dispose();
|
||||
_modConfigService.Dispose();
|
||||
@@ -61,79 +81,215 @@ public sealed class PackageManagementService : IPackageManagementService
|
||||
if (IsDisposed)
|
||||
return FluentResults.Result.Fail($"{nameof(PackageManagementService)}failed to reset. Has already been disposed.");
|
||||
|
||||
var operationResult = new FluentResults.Result();
|
||||
CombineResultErrors(operationResult, UnsafeStopRunningPackagesInternal());
|
||||
CombineResultErrors(operationResult, UnsafeUnloadAllPackagesInternal());
|
||||
return operationResult;
|
||||
|
||||
void CombineResultErrors(FluentResults.Result result,
|
||||
ImmutableArray<(ContentPackage Package, FluentResults.Result OperationResult)> packRes)
|
||||
try
|
||||
{
|
||||
if (packRes.IsDefaultOrEmpty)
|
||||
return;
|
||||
|
||||
foreach (var r in packRes)
|
||||
{
|
||||
if (r.OperationResult.IsSuccess)
|
||||
continue;
|
||||
_logger.LogResults(r.OperationResult);
|
||||
result.WithErrors(r.OperationResult.Errors);
|
||||
}
|
||||
var operationResult = new FluentResults.Result();
|
||||
operationResult.WithReasons(_configService.Reset().Reasons);
|
||||
operationResult.WithReasons(_luaScriptManagementService.Reset().Reasons);
|
||||
operationResult.WithReasons(_pluginManagementService.Reset().Reasons);
|
||||
_runningPackages.Clear();
|
||||
_loadedPackages.Clear();
|
||||
return operationResult;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return FluentResults.Result.Fail(new ExceptionalError(e));
|
||||
}
|
||||
}
|
||||
|
||||
public FluentResults.Result LoadPackageInfo(ContentPackage package)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
Guard.IsNotNull(package, nameof(package));
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
|
||||
IService.CheckDisposed(this);
|
||||
if (_loadedPackages.TryGetValue(package, out var result))
|
||||
{
|
||||
_logger.LogWarning($"{nameof(LoadPackageInfo)}: Tried to load already-loaded package {package.Name}.");
|
||||
return FluentResults.Result.Ok();
|
||||
}
|
||||
|
||||
var pkgCfgInfo = _modConfigService.CreateConfigAsync(package).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
if (pkgCfgInfo.IsFailed)
|
||||
{
|
||||
_logger.LogResults(pkgCfgInfo.ToResult());
|
||||
return pkgCfgInfo.ToResult();
|
||||
}
|
||||
return UnsafeAddPackageInternal(package, pkgCfgInfo.Value);
|
||||
}
|
||||
|
||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result LoadSuccessResult)> LoadPackagesInfo(IReadOnlyCollection<ContentPackage> packages)
|
||||
public FluentResults.Result LoadPackagesInfo(ImmutableArray<ContentPackage> packages)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
if (packages.IsDefaultOrEmpty)
|
||||
ThrowHelper.ThrowArgumentException($"{nameof(LoadPackagesInfo)}: packages list is empty.");
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
|
||||
IService.CheckDisposed(this);
|
||||
var result = new FluentResults.Result();
|
||||
var pkgConfigs = _modConfigService.CreateConfigsAsync([..packages]).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
foreach (var pkgConfig in pkgConfigs)
|
||||
{
|
||||
result.WithReasons(pkgConfig.Config.Reasons);
|
||||
if (pkgConfig.Config.IsSuccess)
|
||||
result.WithReasons(UnsafeAddPackageInternal(pkgConfig.Source, pkgConfig.Config.Value).Reasons);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private FluentResults.Result UnsafeLoadPackageInfoInternal(ContentPackage package)
|
||||
private FluentResults.Result UnsafeAddPackageInternal(ContentPackage package, IModConfigInfo config)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
if (_loadedPackages.TryGetValue(package, out var result))
|
||||
{
|
||||
_logger.LogWarning($"Tried to load already-loaded package {package.Name}.");
|
||||
return FluentResults.Result.Ok();
|
||||
}
|
||||
|
||||
_loadedPackages[package] = config;
|
||||
var res = new FluentResults.Result();
|
||||
res.WithReasons(_luaScriptManagementService.LoadScriptResourcesAsync(config.LuaScripts).ConfigureAwait(false).GetAwaiter().GetResult().Reasons);
|
||||
return res;
|
||||
}
|
||||
|
||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result ExecutionResult)> ExecuteLoadedPackages()
|
||||
public FluentResults.Result ExecuteLoadedPackages(ImmutableArray<ContentPackage> executionOrder)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
using var executeLock = _executionLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
|
||||
private ImmutableArray<(ContentPackage Package, FluentResults.Result StopExectionResult)> UnsafeStopRunningPackagesInternal()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
if (executionOrder.IsDefaultOrEmpty)
|
||||
return FluentResults.Result.Fail($"{nameof(ExecuteLoadedPackages)}: No packages in the execution order list.");
|
||||
|
||||
if (!_runningPackages.IsEmpty)
|
||||
{
|
||||
return FluentResults.Result.Fail(
|
||||
$"{nameof(ExecuteLoadedPackages)}: There are already packages running! List: {
|
||||
_runningPackages.Aggregate(string.Empty, (acc, kvp) => "-" + kvp + "\n" + kvp.Key.Name)}");
|
||||
}
|
||||
|
||||
if (_loadedPackages.IsEmpty)
|
||||
return FluentResults.Result.Fail($"{nameof(ExecuteLoadedPackages)}: No packages loaded. Nothing to run!)");
|
||||
|
||||
var result = new FluentResults.Result();
|
||||
|
||||
// get loading order. Note: packages not in the execution order list will load first.
|
||||
var loadingOrderedPackages = _loadedPackages.OrderBy(pkg => executionOrder.IndexOf(pkg.Key))
|
||||
.ToImmutableArray();
|
||||
|
||||
//mod settings
|
||||
var settings = loadingOrderedPackages
|
||||
.SelectMany(pkg => pkg.Value.Configs.OrderBy(scr => scr.LoadPriority))
|
||||
.ToImmutableArray();
|
||||
if (!settings.IsDefaultOrEmpty)
|
||||
{
|
||||
result.WithReasons(_configService.LoadConfigsAsync(settings).ConfigureAwait(false).GetAwaiter()
|
||||
.GetResult().Reasons);
|
||||
result.WithReasons(_configService.LoadConfigsProfilesAsync(settings).ConfigureAwait(false)
|
||||
.GetAwaiter().GetResult().Reasons);
|
||||
}
|
||||
|
||||
//lua scripts
|
||||
var luaScripts = loadingOrderedPackages
|
||||
.SelectMany(pkg => pkg.Value.LuaScripts.OrderBy(scr => scr.LoadPriority))
|
||||
.ToImmutableArray();
|
||||
if (!luaScripts.IsDefaultOrEmpty)
|
||||
result.WithReasons(_luaScriptManagementService.ExecuteLoadedScripts(luaScripts).Reasons);
|
||||
|
||||
if (_runConfig.IsCsEnabled)
|
||||
{
|
||||
var plugins =
|
||||
loadingOrderedPackages.SelectMany(pkg => pkg.Value.Assemblies.OrderBy(scr => scr.LoadPriority))
|
||||
.ToImmutableArray();
|
||||
if (!plugins.IsDefaultOrEmpty)
|
||||
result.WithReasons(_pluginManagementService.LoadAssemblyResources(plugins).Reasons);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result StopExecutionResult)> StopRunningPackages()
|
||||
public FluentResults.Result StopRunningPackages()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
private FluentResults.Result UnsafeUnloadPackageInternal(ContentPackage package)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
private ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnsafeUnloadAllPackagesInternal()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
using var executeLock = _executionLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
|
||||
if (_loadedPackages.IsEmpty || _runningPackages.IsEmpty)
|
||||
{
|
||||
_logger.LogWarning($"{nameof(StopRunningPackages)}: No packages are currently executing.");
|
||||
return FluentResults.Result.Ok();
|
||||
}
|
||||
|
||||
var res = new FluentResults.Result();
|
||||
res.WithReasons(_luaScriptManagementService.UnloadActiveScripts().Reasons);
|
||||
res.WithReasons(_pluginManagementService.UnloadManagedAssemblies().Reasons);
|
||||
_runningPackages.Clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
public FluentResults.Result UnloadPackage(ContentPackage package)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
Guard.IsNotNull(package, nameof(package));
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
|
||||
if (!_loadedPackages.ContainsKey(package))
|
||||
return FluentResults.Result.Fail($"{nameof(UnloadPackage)}: The package is not loaded.");
|
||||
if (!_runningPackages.IsEmpty)
|
||||
return FluentResults.Result.Fail($"{nameof(UnloadPackage)}: Packages are currently executing.");
|
||||
var result = new FluentResults.Result();
|
||||
result.WithReasons(_luaScriptManagementService.DisposePackageResources(package).Reasons);
|
||||
result.WithReasons(_configService.DisposePackageData(package).Reasons);
|
||||
_loadedPackages.TryRemove(package, out _);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnloadPackages(IReadOnlyCollection<ContentPackage> packages)
|
||||
public FluentResults.Result UnloadPackages(ImmutableArray<ContentPackage> packages)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
if (packages.IsDefaultOrEmpty)
|
||||
return FluentResults.Result.Fail($"{nameof(UnloadPackages)}: Package list is empty.");
|
||||
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
|
||||
var result = new FluentResults.Result();
|
||||
foreach (var package in packages)
|
||||
result.WithReasons(UnloadPackage(package).Reasons);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<(ContentPackage Package, FluentResults.Result UnloadSuccessResult)> UnloadAllPackages()
|
||||
public FluentResults.Result UnloadAllPackages()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
using var lck = _operationsLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
using var executeLock = _executionLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
|
||||
if (_loadedPackages.IsEmpty)
|
||||
return FluentResults.Result.Ok();
|
||||
if (!_runningPackages.IsEmpty)
|
||||
return FluentResults.Result.Fail($"{nameof(UnloadAllPackages)}: Packages are currently executing.");
|
||||
var result = new FluentResults.Result();
|
||||
result.WithReasons(_luaScriptManagementService.DisposeAllPackageResources().Reasons);
|
||||
result.WithReasons(_configService.DisposeAllPackageData().Reasons);
|
||||
_loadedPackages.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImmutableArray<ContentPackage> GetAllLoadedPackages()
|
||||
{
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
return [.._loadedPackages.Keys];
|
||||
}
|
||||
|
||||
public bool IsPackageRunning(ContentPackage package)
|
||||
{
|
||||
Guard.IsNotNull(package, nameof(package));
|
||||
using var lck = _operationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
return _runningPackages.ContainsKey(package);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user