84 lines
2.9 KiB
C#
84 lines
2.9 KiB
C#
using System.Text.Json;
|
|
|
|
namespace AcDream.Launcher.Core.Updates;
|
|
|
|
internal static class AtomicJsonFile
|
|
{
|
|
internal static async Task WriteAsync<T>(
|
|
string path,
|
|
T value,
|
|
JsonSerializerOptions options,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
string fullPath = Path.GetFullPath(path);
|
|
string directory = Path.GetDirectoryName(fullPath)
|
|
?? throw new InvalidOperationException("The JSON path has no parent directory.");
|
|
Directory.CreateDirectory(directory);
|
|
string temporaryPath = Path.Combine(
|
|
directory,
|
|
$".{Path.GetFileName(fullPath)}.{Guid.NewGuid():N}.tmp");
|
|
try
|
|
{
|
|
await using (var stream = new FileStream(
|
|
temporaryPath,
|
|
FileMode.CreateNew,
|
|
FileAccess.Write,
|
|
FileShare.None,
|
|
16 * 1024,
|
|
FileOptions.Asynchronous | FileOptions.WriteThrough))
|
|
{
|
|
await JsonSerializer.SerializeAsync(
|
|
stream,
|
|
value,
|
|
options,
|
|
cancellationToken)
|
|
.ConfigureAwait(false);
|
|
await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
|
stream.Flush(flushToDisk: true);
|
|
}
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
File.Move(temporaryPath, fullPath, overwrite: true);
|
|
}
|
|
finally
|
|
{
|
|
VerifiedArtifactDownloader.TryDelete(temporaryPath);
|
|
}
|
|
}
|
|
|
|
internal static async Task WriteBytesAsync(
|
|
string path,
|
|
ReadOnlyMemory<byte> bytes,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
string fullPath = Path.GetFullPath(path);
|
|
string directory = Path.GetDirectoryName(fullPath)
|
|
?? throw new InvalidOperationException("The file path has no parent directory.");
|
|
Directory.CreateDirectory(directory);
|
|
string temporaryPath = Path.Combine(
|
|
directory,
|
|
$".{Path.GetFileName(fullPath)}.{Guid.NewGuid():N}.tmp");
|
|
try
|
|
{
|
|
await using (var stream = new FileStream(
|
|
temporaryPath,
|
|
FileMode.CreateNew,
|
|
FileAccess.Write,
|
|
FileShare.None,
|
|
16 * 1024,
|
|
FileOptions.Asynchronous | FileOptions.WriteThrough))
|
|
{
|
|
await stream.WriteAsync(bytes, cancellationToken).ConfigureAwait(false);
|
|
await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
|
stream.Flush(flushToDisk: true);
|
|
}
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
File.Move(temporaryPath, fullPath, overwrite: true);
|
|
}
|
|
finally
|
|
{
|
|
VerifiedArtifactDownloader.TryDelete(temporaryPath);
|
|
}
|
|
}
|
|
}
|