The deadlock situation is craaaaazy
Fix
This commit is contained in:
committed by
Maplewheels
parent
dda26df250
commit
f1e1b9238d
+7
-1
@@ -235,6 +235,12 @@ public sealed class ModConfigService : IModConfigService
|
|||||||
|
|
||||||
private async Task<Result<IModConfigInfo>> CreateFromLegacyAsync(ContentPackage src)
|
private async Task<Result<IModConfigInfo>> CreateFromLegacyAsync(ContentPackage src)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return new ModConfigInfo()
|
||||||
|
{
|
||||||
|
Package = src,
|
||||||
|
Assemblies = ImmutableArray<IAssemblyResourceInfo>.Empty,
|
||||||
|
Configs = ImmutableArray<IConfigResourceInfo>.Empty,
|
||||||
|
LuaScripts = ImmutableArray<ILuaScriptResourceInfo>.Empty
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ public class SafeStorageService : StorageService, ISafeStorageService
|
|||||||
|
|
||||||
public SafeStorageService(IStorageServiceConfig configData) : base(configData)
|
public SafeStorageService(IStorageServiceConfig configData) : base(configData)
|
||||||
{
|
{
|
||||||
IsReadOperationAllowedEval = async Task<bool> (fp) => IsFileAccessible(fp, true, true);
|
IsReadOperationAllowedEval = (fp) => IsFileAccessible(fp, true, true);
|
||||||
IsWriteOperationAllowedEval = async Task<bool> (fp) => IsFileAccessible(fp, false, true);
|
IsWriteOperationAllowedEval = (fp) => IsFileAccessible(fp, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFullPath(string path) => System.IO.Path.GetFullPath(path).CleanUpPathCrossPlatform();
|
private string GetFullPath(string path) => System.IO.Path.GetFullPath(path).CleanUpPathCrossPlatform();
|
||||||
|
|||||||
@@ -17,7 +17,10 @@ public class ServicesProvider : IServicesProvider
|
|||||||
|
|
||||||
public ServicesProvider()
|
public ServicesProvider()
|
||||||
{
|
{
|
||||||
_serviceContainerInst = new ServiceContainer();
|
_serviceContainerInst = new ServiceContainer(new ContainerOptions()
|
||||||
|
{
|
||||||
|
EnablePropertyInjection = false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterServiceType<TSvcInterface, TService>(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface
|
public void RegisterServiceType<TSvcInterface, TService>(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface
|
||||||
|
|||||||
@@ -23,27 +23,16 @@ public class StorageService : IStorageService
|
|||||||
public StorageService(IStorageServiceConfig configData)
|
public StorageService(IStorageServiceConfig configData)
|
||||||
{
|
{
|
||||||
ConfigData = configData;
|
ConfigData = configData;
|
||||||
IsReadOperationAllowedEval = async Task<bool> (str) => true;
|
IsReadOperationAllowedEval = bool (str) => true;
|
||||||
IsWriteOperationAllowedEval = async Task<bool> (str) => true;
|
IsWriteOperationAllowedEval = bool (str) => true;
|
||||||
}
|
|
||||||
|
|
||||||
public StorageService(IStorageServiceConfig configData,
|
|
||||||
Func<string, Task<bool>> isReadOperationAllowedEval,
|
|
||||||
Func<string, Task<bool>> isWriteOperationAllowedEval)
|
|
||||||
{
|
|
||||||
Guard.IsNotNull(isReadOperationAllowedEval, nameof(isReadOperationAllowedEval));
|
|
||||||
Guard.IsNotNull(isWriteOperationAllowedEval, nameof(isWriteOperationAllowedEval));
|
|
||||||
ConfigData = configData;
|
|
||||||
IsReadOperationAllowedEval = isReadOperationAllowedEval;
|
|
||||||
IsWriteOperationAllowedEval = isWriteOperationAllowedEval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, OneOf.OneOf<byte[], string, XDocument>> _fsCache = new();
|
private readonly ConcurrentDictionary<string, OneOf.OneOf<byte[], string, XDocument>> _fsCache = new();
|
||||||
protected readonly IStorageServiceConfig ConfigData;
|
protected readonly IStorageServiceConfig ConfigData;
|
||||||
protected readonly AsyncReaderWriterLock OperationsLock = new();
|
protected readonly AsyncReaderWriterLock OperationsLock = new();
|
||||||
|
|
||||||
private Func<string, Task<bool>> _isReadOperationAllowedEval;
|
private Func<string, bool> _isReadOperationAllowedEval;
|
||||||
protected Func<string, Task<bool>> IsReadOperationAllowedEval
|
protected Func<string, bool> IsReadOperationAllowedEval
|
||||||
{
|
{
|
||||||
get => _isReadOperationAllowedEval;
|
get => _isReadOperationAllowedEval;
|
||||||
set
|
set
|
||||||
@@ -53,8 +42,8 @@ public class StorageService : IStorageService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Func<string, Task<bool>> _isWriteOperationAllowedEval;
|
private Func<string, bool> _isWriteOperationAllowedEval;
|
||||||
protected Func<string, Task<bool>> IsWriteOperationAllowedEval
|
protected Func<string, bool> IsWriteOperationAllowedEval
|
||||||
{
|
{
|
||||||
get => _isWriteOperationAllowedEval;
|
get => _isWriteOperationAllowedEval;
|
||||||
set
|
set
|
||||||
@@ -221,25 +210,28 @@ public class StorageService : IStorageService
|
|||||||
public async Task<FluentResults.Result> SaveLocalTextAsync(ContentPackage package, string localFilePath, string text)
|
public async Task<FluentResults.Result> SaveLocalTextAsync(ContentPackage package, string localFilePath, string text)
|
||||||
=> await SaveLocalDataAsync(package, localFilePath, text, async (path, txt) => await TrySaveTextAsync(path, txt));
|
=> await SaveLocalDataAsync(package, localFilePath, text, async (path, txt) => await TrySaveTextAsync(path, txt));
|
||||||
|
|
||||||
|
private bool IsPackagePathValid(ContentPath contentPath)
|
||||||
|
{
|
||||||
|
return contentPath.FullPath.StartsWith(ConfigData.WorkshopModsDirectory)
|
||||||
|
|| contentPath.FullPath.StartsWith(ConfigData.LocalModsDirectory)
|
||||||
|
#if CLIENT
|
||||||
|
|| contentPath.FullPath.StartsWith(ConfigData.TempDownloadsDirectory)
|
||||||
|
#endif
|
||||||
|
|| contentPath.FullPath.StartsWith(Path.GetFullPath(ContentPackageManager.VanillaCorePackage!.Dir).CleanUpPathCrossPlatform());
|
||||||
|
}
|
||||||
|
|
||||||
// --- Package Content
|
// --- Package Content
|
||||||
private Result<T> LoadPackageData<T>(ContentPath filePath, Func<string, Result<T>> dataLoader)
|
private Result<T> LoadPackageData<T>(ContentPath contentPath, Func<string, Result<T>> dataLoader)
|
||||||
{
|
{
|
||||||
Guard.IsNotNull(filePath, nameof(filePath));
|
Guard.IsNotNull(contentPath, nameof(contentPath));
|
||||||
Guard.IsNotNullOrWhiteSpace(filePath.FullPath, nameof(filePath.FullPath));
|
Guard.IsNotNullOrWhiteSpace(contentPath.FullPath, nameof(contentPath.FullPath));
|
||||||
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
if (!filePath.FullPath.StartsWith(ConfigData.WorkshopModsDirectory)
|
if (!IsPackagePathValid(contentPath))
|
||||||
&& !filePath.FullPath.StartsWith(ConfigData.LocalModsDirectory)
|
|
||||||
&& !filePath.FullPath.StartsWith(ContentPackageManager.VanillaCorePackage!.Dir)
|
|
||||||
#if CLIENT
|
|
||||||
&& !filePath.FullPath.StartsWith(ConfigData.TempDownloadsDirectory)
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
ThrowHelper.ThrowUnauthorizedAccessException($"{nameof(LoadPackageData)}: The filepath of `{filePath.FullPath}' is not in a package directory!");
|
ThrowHelper.ThrowUnauthorizedAccessException($"{nameof(LoadPackageData)}: The filepath of `{contentPath.FullPath}' is not in a package directory!");
|
||||||
}
|
}
|
||||||
return dataLoader(filePath.FullPath);
|
return dataLoader(contentPath.FullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<XDocument> LoadPackageXml(ContentPath filePath)
|
public Result<XDocument> LoadPackageXml(ContentPath filePath)
|
||||||
@@ -292,18 +284,17 @@ public class StorageService : IStorageService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<Result<T>> LoadPackageDataAsync<T>(ContentPath filePath, Func<string, Task<Result<T>>> dataLoader)
|
private async Task<Result<T>> LoadPackageDataAsync<T>(ContentPath contentPath, Func<string, Task<Result<T>>> dataLoader)
|
||||||
{
|
{
|
||||||
Guard.IsNotNull(filePath, nameof(filePath));
|
Guard.IsNotNull(contentPath, nameof(contentPath));
|
||||||
Guard.IsNotNullOrWhiteSpace(filePath.FullPath, nameof(filePath.FullPath));
|
Guard.IsNotNullOrWhiteSpace(contentPath.FullPath, nameof(contentPath.FullPath));
|
||||||
using var lck = await OperationsLock.AcquireReaderLock();
|
using var lck = await OperationsLock.AcquireReaderLock();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
if (!filePath.FullPath.StartsWith(ConfigData.WorkshopModsDirectory) && !filePath.FullPath.StartsWith(ConfigData.LocalModsDirectory))
|
if (!IsPackagePathValid(contentPath))
|
||||||
{
|
{
|
||||||
ThrowHelper.ThrowUnauthorizedAccessException(
|
ThrowHelper.ThrowUnauthorizedAccessException($"{nameof(LoadPackageDataAsync)}: The filepath of `{contentPath.FullPath}' is not in a package directory!");
|
||||||
$"{nameof(LoadPackageData)}: The filepath of `{filePath.FullPath}' is not in a package directory!");
|
|
||||||
}
|
}
|
||||||
return await dataLoader(filePath.FullPath);
|
return await dataLoader(contentPath.FullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Result<XDocument>> LoadPackageXmlAsync(ContentPath filePath)
|
public async Task<Result<XDocument>> LoadPackageXmlAsync(ContentPath filePath)
|
||||||
@@ -371,7 +362,7 @@ public class StorageService : IStorageService
|
|||||||
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
if (IsReadOperationAllowedEval?.Invoke(filePath).ConfigureAwait(false).GetAwaiter().GetResult() is not true)
|
if (IsReadOperationAllowedEval?.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TryLoadText)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TryLoadText)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -399,7 +390,7 @@ public class StorageService : IStorageService
|
|||||||
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
if (IsReadOperationAllowedEval?.Invoke(filePath).ConfigureAwait(false).GetAwaiter().GetResult() is not true)
|
if (IsReadOperationAllowedEval?.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TryLoadBinary)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TryLoadBinary)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -430,7 +421,7 @@ public class StorageService : IStorageService
|
|||||||
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
if (IsWriteOperationAllowedEval?.Invoke(filePath).ConfigureAwait(false).GetAwaiter().GetResult() is not true)
|
if (IsWriteOperationAllowedEval?.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TrySaveText)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TrySaveText)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -456,7 +447,7 @@ public class StorageService : IStorageService
|
|||||||
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
using var lck = OperationsLock.AcquireReaderLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
|
|
||||||
if (IsWriteOperationAllowedEval?.Invoke(filePath).ConfigureAwait(false).GetAwaiter().GetResult() is not true)
|
if (IsWriteOperationAllowedEval?.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TrySaveBinary)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TrySaveBinary)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -479,7 +470,7 @@ public class StorageService : IStorageService
|
|||||||
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
// lock not needed
|
// lock not needed
|
||||||
if (IsReadOperationAllowedEval?.Invoke(filePath).ConfigureAwait(false).GetAwaiter().GetResult() is not true)
|
if (IsReadOperationAllowedEval?.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(FileExists)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(FileExists)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -497,7 +488,7 @@ public class StorageService : IStorageService
|
|||||||
Guard.IsNotNullOrWhiteSpace(directoryPath, nameof(directoryPath));
|
Guard.IsNotNullOrWhiteSpace(directoryPath, nameof(directoryPath));
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
// lock not needed
|
// lock not needed
|
||||||
if (IsReadOperationAllowedEval?.Invoke(directoryPath).ConfigureAwait(false).GetAwaiter().GetResult() is not true)
|
if (IsReadOperationAllowedEval?.Invoke(directoryPath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(DirectoryExists)}: File '{directoryPath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(DirectoryExists)}: File '{directoryPath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -518,7 +509,7 @@ public class StorageService : IStorageService
|
|||||||
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
||||||
using var lck = await OperationsLock.AcquireReaderLock();
|
using var lck = await OperationsLock.AcquireReaderLock();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
if (await IsReadOperationAllowedEval.Invoke(filePath) is not true)
|
if (IsReadOperationAllowedEval.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TryLoadXmlAsync)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TryLoadXmlAsync)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -548,7 +539,7 @@ public class StorageService : IStorageService
|
|||||||
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
||||||
using var lck = await OperationsLock.AcquireReaderLock();
|
using var lck = await OperationsLock.AcquireReaderLock();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
if (await IsReadOperationAllowedEval.Invoke(filePath) is not true)
|
if (IsReadOperationAllowedEval.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TryLoadTextAsync)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TryLoadTextAsync)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -575,7 +566,7 @@ public class StorageService : IStorageService
|
|||||||
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
Guard.IsNotNullOrWhiteSpace(filePath, nameof(filePath));
|
||||||
using var lck = await OperationsLock.AcquireReaderLock();
|
using var lck = await OperationsLock.AcquireReaderLock();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
if (await IsReadOperationAllowedEval.Invoke(filePath) is not true)
|
if (IsReadOperationAllowedEval.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TryLoadBinaryAsync)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TryLoadBinaryAsync)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -601,7 +592,7 @@ public class StorageService : IStorageService
|
|||||||
Guard.IsNotNullOrWhiteSpace(text, nameof(text));
|
Guard.IsNotNullOrWhiteSpace(text, nameof(text));
|
||||||
using var lck = await OperationsLock.AcquireReaderLock();
|
using var lck = await OperationsLock.AcquireReaderLock();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
if (await IsWriteOperationAllowedEval.Invoke(filePath) is not true)
|
if (IsWriteOperationAllowedEval.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TrySaveTextAsync)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TrySaveTextAsync)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
@@ -625,7 +616,7 @@ public class StorageService : IStorageService
|
|||||||
Guard.HasSizeGreaterThanOrEqualTo(bytes, 1, nameof(bytes));
|
Guard.HasSizeGreaterThanOrEqualTo(bytes, 1, nameof(bytes));
|
||||||
using var lck = await OperationsLock.AcquireReaderLock();
|
using var lck = await OperationsLock.AcquireReaderLock();
|
||||||
IService.CheckDisposed(this);
|
IService.CheckDisposed(this);
|
||||||
if (await IsWriteOperationAllowedEval.Invoke(filePath) is not true)
|
if (IsWriteOperationAllowedEval.Invoke(filePath) is not true)
|
||||||
{
|
{
|
||||||
return FluentResults.Result.Fail($"{nameof(TrySaveBinaryAsync)}: File '{filePath}' is not allowed.");
|
return FluentResults.Result.Fail($"{nameof(TrySaveBinaryAsync)}: File '{filePath}' is not allowed.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user