80 lines
2.4 KiB
C#
80 lines
2.4 KiB
C#
using AcDream.Platform;
|
|
|
|
namespace AcDream.Bake;
|
|
|
|
/// <summary>
|
|
/// Optional launcher authorization checked immediately before atomic
|
|
/// publication. Standalone Bake runs have no nonce environment variable and
|
|
/// retain the original unguarded behavior.
|
|
/// </summary>
|
|
internal static class BakePublicationGuard
|
|
{
|
|
private static readonly TimeSpan RetryDelay = TimeSpan.FromMilliseconds(50);
|
|
|
|
internal static IDisposable? AcquireIfRequested(
|
|
string outputPath,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
string? nonce = Environment.GetEnvironmentVariable(
|
|
BakePublicationGuardPaths.NonceEnvironmentVariable);
|
|
if (nonce is null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (!BakePublicationGuardPaths.IsValidNonce(nonce))
|
|
{
|
|
throw new InvalidOperationException(
|
|
"The launcher bake publication nonce is invalid.");
|
|
}
|
|
|
|
string lockPath = BakePublicationGuardPaths.GetPublishLockPath(
|
|
outputPath);
|
|
Directory.CreateDirectory(
|
|
Path.GetDirectoryName(lockPath)
|
|
?? throw new InvalidOperationException(
|
|
"The bake publication lock has no parent directory."));
|
|
|
|
FileStream? lease = null;
|
|
while (lease is null)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
try
|
|
{
|
|
lease = new FileStream(
|
|
lockPath,
|
|
FileMode.OpenOrCreate,
|
|
FileAccess.ReadWrite,
|
|
FileShare.None,
|
|
bufferSize: 1,
|
|
options: FileOptions.None);
|
|
}
|
|
catch (IOException)
|
|
{
|
|
cancellationToken.WaitHandle.WaitOne(RetryDelay);
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
string authorizationPath =
|
|
BakePublicationGuardPaths.GetAuthorizationPath(outputPath);
|
|
string authorized = File.Exists(authorizationPath)
|
|
? File.ReadAllText(authorizationPath)
|
|
: string.Empty;
|
|
if (!string.Equals(authorized, nonce, StringComparison.Ordinal))
|
|
{
|
|
throw new InvalidOperationException(
|
|
"This bake process is no longer authorized to publish its output.");
|
|
}
|
|
|
|
return lease;
|
|
}
|
|
catch
|
|
{
|
|
lease.Dispose();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
}
|