Use file-scoped namespaces

This commit is contained in:
Archi
2021-11-10 21:23:24 +01:00
parent 95ad16e26d
commit 1e6ab11d9f
142 changed files with 25006 additions and 25006 deletions

View File

@@ -27,180 +27,180 @@ using System.Threading;
using System.Threading.Tasks;
using ArchiSteamFarm.Core;
namespace ArchiSteamFarm.Helpers {
internal sealed class CrossProcessFileBasedSemaphore : ICrossProcessSemaphore, IDisposable {
private const ushort SpinLockDelay = 1000; // In milliseconds
namespace ArchiSteamFarm.Helpers;
private readonly string FilePath;
private readonly SemaphoreSlim LocalSemaphore = new(1, 1);
internal sealed class CrossProcessFileBasedSemaphore : ICrossProcessSemaphore, IDisposable {
private const ushort SpinLockDelay = 1000; // In milliseconds
private FileStream? FileLock;
private readonly string FilePath;
private readonly SemaphoreSlim LocalSemaphore = new(1, 1);
internal CrossProcessFileBasedSemaphore(string name) {
if (string.IsNullOrEmpty(name)) {
throw new ArgumentNullException(nameof(name));
}
private FileStream? FileLock;
FilePath = Path.Combine(Path.GetTempPath(), SharedInfo.ASF, name);
EnsureFileExists();
internal CrossProcessFileBasedSemaphore(string name) {
if (string.IsNullOrEmpty(name)) {
throw new ArgumentNullException(nameof(name));
}
public void Dispose() {
LocalSemaphore.Dispose();
FilePath = Path.Combine(Path.GetTempPath(), SharedInfo.ASF, name);
FileLock?.Dispose();
}
EnsureFileExists();
}
void ICrossProcessSemaphore.Release() {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (LocalSemaphore) {
if (FileLock == null) {
throw new InvalidOperationException(nameof(FileLock));
}
public void Dispose() {
LocalSemaphore.Dispose();
FileLock.Dispose();
FileLock = null;
FileLock?.Dispose();
}
void ICrossProcessSemaphore.Release() {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (LocalSemaphore) {
if (FileLock == null) {
throw new InvalidOperationException(nameof(FileLock));
}
LocalSemaphore.Release();
FileLock.Dispose();
FileLock = null;
}
async Task ICrossProcessSemaphore.WaitAsync() {
await LocalSemaphore.WaitAsync().ConfigureAwait(false);
LocalSemaphore.Release();
}
bool success = false;
async Task ICrossProcessSemaphore.WaitAsync() {
await LocalSemaphore.WaitAsync().ConfigureAwait(false);
try {
while (true) {
try {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (LocalSemaphore) {
if (FileLock != null) {
throw new InvalidOperationException(nameof(FileLock));
}
bool success = false;
EnsureFileExists();
FileLock = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None);
success = true;
return;
}
} catch (IOException) {
await Task.Delay(SpinLockDelay).ConfigureAwait(false);
}
}
} finally {
if (!success) {
LocalSemaphore.Release();
}
}
}
async Task<bool> ICrossProcessSemaphore.WaitAsync(int millisecondsTimeout) {
Stopwatch stopwatch = Stopwatch.StartNew();
if (!await LocalSemaphore.WaitAsync(millisecondsTimeout).ConfigureAwait(false)) {
stopwatch.Stop();
return false;
}
bool success = false;
try {
stopwatch.Stop();
millisecondsTimeout -= (int) stopwatch.ElapsedMilliseconds;
if (millisecondsTimeout <= 0) {
return false;
}
while (true) {
try {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (LocalSemaphore) {
if (FileLock != null) {
throw new InvalidOperationException(nameof(FileLock));
}
EnsureFileExists();
FileLock = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None);
success = true;
return true;
}
} catch (IOException) {
if (millisecondsTimeout <= SpinLockDelay) {
return false;
try {
while (true) {
try {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (LocalSemaphore) {
if (FileLock != null) {
throw new InvalidOperationException(nameof(FileLock));
}
await Task.Delay(SpinLockDelay).ConfigureAwait(false);
millisecondsTimeout -= SpinLockDelay;
EnsureFileExists();
FileLock = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None);
success = true;
return;
}
}
} finally {
if (!success) {
LocalSemaphore.Release();
} catch (IOException) {
await Task.Delay(SpinLockDelay).ConfigureAwait(false);
}
}
}
private void EnsureFileExists() {
if (File.Exists(FilePath)) {
return;
}
string? directoryPath = Path.GetDirectoryName(FilePath);
if (string.IsNullOrEmpty(directoryPath)) {
ASF.ArchiLogger.LogNullError(nameof(directoryPath));
return;
}
if (!Directory.Exists(directoryPath)) {
Directory.CreateDirectory(directoryPath);
if (OperatingSystem.IsWindows()) {
DirectoryInfo directoryInfo = new(directoryPath);
try {
DirectorySecurity directorySecurity = new(directoryPath, AccessControlSections.All);
directoryInfo.SetAccessControl(directorySecurity);
} catch (PrivilegeNotHeldException e) {
// Non-critical, user might have no rights to manage the resource
ASF.ArchiLogger.LogGenericDebuggingException(e);
}
} else if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
OS.UnixSetFileAccess(directoryPath!, OS.EUnixPermission.Combined777);
}
}
try {
new FileStream(FilePath, FileMode.CreateNew).Dispose();
if (OperatingSystem.IsWindows()) {
FileInfo fileInfo = new(FilePath);
try {
FileSecurity fileSecurity = new(FilePath, AccessControlSections.All);
fileInfo.SetAccessControl(fileSecurity);
} catch (PrivilegeNotHeldException e) {
// Non-critical, user might have no rights to manage the resource
ASF.ArchiLogger.LogGenericDebuggingException(e);
}
} else if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
OS.UnixSetFileAccess(FilePath, OS.EUnixPermission.Combined777);
}
} catch (IOException) {
// Ignored, if the file was already created in the meantime by another instance, this is fine
} finally {
if (!success) {
LocalSemaphore.Release();
}
}
}
async Task<bool> ICrossProcessSemaphore.WaitAsync(int millisecondsTimeout) {
Stopwatch stopwatch = Stopwatch.StartNew();
if (!await LocalSemaphore.WaitAsync(millisecondsTimeout).ConfigureAwait(false)) {
stopwatch.Stop();
return false;
}
bool success = false;
try {
stopwatch.Stop();
millisecondsTimeout -= (int) stopwatch.ElapsedMilliseconds;
if (millisecondsTimeout <= 0) {
return false;
}
while (true) {
try {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (LocalSemaphore) {
if (FileLock != null) {
throw new InvalidOperationException(nameof(FileLock));
}
EnsureFileExists();
FileLock = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.None);
success = true;
return true;
}
} catch (IOException) {
if (millisecondsTimeout <= SpinLockDelay) {
return false;
}
await Task.Delay(SpinLockDelay).ConfigureAwait(false);
millisecondsTimeout -= SpinLockDelay;
}
}
} finally {
if (!success) {
LocalSemaphore.Release();
}
}
}
private void EnsureFileExists() {
if (File.Exists(FilePath)) {
return;
}
string? directoryPath = Path.GetDirectoryName(FilePath);
if (string.IsNullOrEmpty(directoryPath)) {
ASF.ArchiLogger.LogNullError(nameof(directoryPath));
return;
}
if (!Directory.Exists(directoryPath)) {
Directory.CreateDirectory(directoryPath);
if (OperatingSystem.IsWindows()) {
DirectoryInfo directoryInfo = new(directoryPath);
try {
DirectorySecurity directorySecurity = new(directoryPath, AccessControlSections.All);
directoryInfo.SetAccessControl(directorySecurity);
} catch (PrivilegeNotHeldException e) {
// Non-critical, user might have no rights to manage the resource
ASF.ArchiLogger.LogGenericDebuggingException(e);
}
} else if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
OS.UnixSetFileAccess(directoryPath!, OS.EUnixPermission.Combined777);
}
}
try {
new FileStream(FilePath, FileMode.CreateNew).Dispose();
if (OperatingSystem.IsWindows()) {
FileInfo fileInfo = new(FilePath);
try {
FileSecurity fileSecurity = new(FilePath, AccessControlSections.All);
fileInfo.SetAccessControl(fileSecurity);
} catch (PrivilegeNotHeldException e) {
// Non-critical, user might have no rights to manage the resource
ASF.ArchiLogger.LogGenericDebuggingException(e);
}
} else if (OperatingSystem.IsFreeBSD() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) {
OS.UnixSetFileAccess(FilePath, OS.EUnixPermission.Combined777);
}
} catch (IOException) {
// Ignored, if the file was already created in the meantime by another instance, this is fine
}
}
}