-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAzureFile.cs
More file actions
165 lines (141 loc) · 6.3 KB
/
Copy pathAzureFile.cs
File metadata and controls
165 lines (141 loc) · 6.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
namespace Ramstack.FileSystem.Azure;
/// <summary>
/// Represents an implementation of <see cref="VirtualFile"/> that maps a file to an Azure Storage blob.
/// </summary>
internal sealed class AzureFile : VirtualFile
{
private readonly AzureFileSystem _fs;
private BlobClient? _client;
/// <inheritdoc />
public override IVirtualFileSystem FileSystem => _fs;
/// <summary>
/// Initializes a new instance of the <see cref="AzureFile"/> class.
/// </summary>
/// <param name="fileSystem">The file system associated with this file.</param>
/// <param name="path">The path to the file.</param>
public AzureFile(AzureFileSystem fileSystem, string path) : base(path) =>
_fs = fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="AzureFile"/> class.
/// </summary>
/// <param name="fileSystem">The file system associated with this file.</param>
/// <param name="path">The path to the file.</param>
/// <param name="properties">The properties of the file, if available.</param>
public AzureFile(AzureFileSystem fileSystem, string path, VirtualNodeProperties? properties) : base(path, properties) =>
_fs = fileSystem;
/// <inheritdoc />
protected override async ValueTask<VirtualNodeProperties?> GetPropertiesCoreAsync(CancellationToken cancellationToken)
{
try
{
BlobProperties info = await GetBlobClient()
.GetPropertiesAsync(cancellationToken: cancellationToken)
.ConfigureAwait(false);
return VirtualNodeProperties.CreateFileProperties(
creationTime: info.CreatedOn,
lastAccessTime: info.LastAccessed,
lastWriteTime: info.LastModified,
length: info.ContentLength);
}
catch (RequestFailedException e) when (e.Status == 404)
{
return null;
}
}
/// <inheritdoc />
protected override ValueTask<Stream> OpenReadCoreAsync(CancellationToken cancellationToken)
{
var task = GetBlobClient().OpenReadAsync(cancellationToken: cancellationToken);
return new ValueTask<Stream>(task);
}
/// <inheritdoc />
protected override ValueTask<Stream> OpenWriteCoreAsync(CancellationToken cancellationToken)
{
var task = GetBlobClient().OpenWriteAsync(overwrite: true, cancellationToken: cancellationToken);
return new ValueTask<Stream>(task);
}
/// <inheritdoc />
protected override ValueTask WriteCoreAsync(Stream stream, bool overwrite, CancellationToken cancellationToken)
{
var options = new BlobUploadOptions();
if (!overwrite)
{
options.Conditions = new BlobRequestConditions
{
IfNoneMatch = new ETag("*")
};
}
var task = GetBlobClient().UploadAsync(stream, options, cancellationToken);
return new ValueTask(task);
}
/// <inheritdoc />
protected override ValueTask DeleteCoreAsync(CancellationToken cancellationToken)
{
var task = GetBlobClient().DeleteIfExistsAsync(
DeleteSnapshotsOption.IncludeSnapshots,
cancellationToken: cancellationToken);
return new ValueTask(task);
}
/// <inheritdoc />
protected override ValueTask CopyToCoreAsync(string destinationPath, bool overwrite, CancellationToken cancellationToken)
{
var source = GetBlobClient();
var destination = _fs.CreateBlobClient(destinationPath);
return CopyBlobAsync(source, destination, overwrite, cancellationToken);
}
/// <inheritdoc />
protected override ValueTask CopyToCoreAsync(VirtualFile destination, bool overwrite, CancellationToken cancellationToken)
{
if (destination is AzureFile file)
return CopyBlobAsync(GetBlobClient(), file.GetBlobClient(), overwrite, cancellationToken);
return base.CopyToCoreAsync(destination, overwrite, cancellationToken);
}
/// <summary>
/// Asynchronously copies a source blob to the specified destination.
/// </summary>
/// <param name="source">The source blob client.</param>
/// <param name="destination">The destination blob client.</param>
/// <param name="overwrite">A boolean value indicating whether to overwrite the destination blob if it already exists.</param>
/// <param name="cancellationToken">An optional cancellation token to cancel the operation.</param>
/// <returns>
/// A <see cref="ValueTask"/> representing the asynchronous operation.
/// </returns>
private async ValueTask CopyBlobAsync(BlobClient source, BlobClient destination, bool overwrite, CancellationToken cancellationToken)
{
if (source.Uri == destination.Uri)
throw new IOException($"Cannot copy a file '{FullName}' to itself.");
var conditions = !overwrite
? new BlobRequestConditions { IfNoneMatch = new ETag("*") }
: null;
var operation = await destination
.StartCopyFromUriAsync(
source.Uri,
destinationConditions: conditions,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
await operation
.WaitForCompletionAsync(
pollingInterval: TimeSpan.FromMilliseconds(100),
cancellationToken)
.ConfigureAwait(false);
BlobProperties properties = await destination
.GetPropertiesAsync(cancellationToken: cancellationToken)
.ConfigureAwait(false);
if (properties.CopyStatus != CopyStatus.Success)
{
var message = $"Error while copying file. {properties.CopyStatus}: {properties.CopyStatusDescription}";
throw new InvalidOperationException(message);
}
}
/// <summary>
/// Returns the <see cref="BlobClient"/> associated with this file.
/// </summary>
/// <returns>
/// The <see cref="BlobClient"/> instance used to manage this blob.
/// </returns>
private BlobClient GetBlobClient() =>
_client ??= _fs.CreateBlobClient(FullName);
}