-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGcsFile.cs
More file actions
162 lines (138 loc) · 6.68 KB
/
Copy pathGcsFile.cs
File metadata and controls
162 lines (138 loc) · 6.68 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
using System.Net;
using Google;
using Google.Cloud.Storage.V1;
namespace Ramstack.FileSystem.Google;
/// <summary>
/// Represents an implementation of <see cref="VirtualFile"/> that maps a file to a Google Cloud Storage object.
/// </summary>
internal sealed class GcsFile : VirtualFile
{
private readonly GoogleFileSystem _fs;
private string? _objectName;
/// <inheritdoc />
public override IVirtualFileSystem FileSystem => _fs;
/// <summary>
/// Initializes a new instance of the <see cref="GcsFile"/> class.
/// </summary>
/// <param name="fileSystem">The file system associated with this file.</param>
/// <param name="path">The path to the file.</param>
public GcsFile(GoogleFileSystem fileSystem, string path) : base(path) =>
_fs = fileSystem;
/// <summary>
/// Initializes a new instance of the <see cref="GcsFile"/> 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 GcsFile(GoogleFileSystem fileSystem, string path, VirtualNodeProperties? properties) : base(path, properties) =>
_fs = fileSystem;
/// <inheritdoc />
protected override async ValueTask<VirtualNodeProperties?> GetPropertiesCoreAsync(CancellationToken cancellationToken)
{
try
{
var obj = await _fs.StorageClient
.GetObjectAsync(_fs.BucketName, GetObjectName(), cancellationToken: cancellationToken)
.ConfigureAwait(false);
return VirtualNodeProperties.CreateFileProperties(
creationTime: obj.TimeCreatedDateTimeOffset.GetValueOrDefault(),
lastAccessTime: default,
lastWriteTime: obj.UpdatedDateTimeOffset.GetValueOrDefault(),
length: (long?)obj.Size ?? 0);
}
catch (GoogleApiException e) when (e.HttpStatusCode == HttpStatusCode.NotFound)
{
return null;
}
}
/// <inheritdoc />
protected override async ValueTask<Stream> OpenReadCoreAsync(CancellationToken cancellationToken)
{
var stream = CreateTempFileStream();
await _fs.StorageClient
.DownloadObjectAsync(_fs.BucketName, GetObjectName(), stream, cancellationToken: cancellationToken)
.ConfigureAwait(false);
stream.Position = 0;
return stream;
static FileStream CreateTempFileStream()
{
const int BufferSize = 4096;
const FileOptions Options = FileOptions.DeleteOnClose | FileOptions.Asynchronous;
var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
return new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, BufferSize, Options);
}
}
/// <inheritdoc />
protected override ValueTask<Stream> OpenWriteCoreAsync(CancellationToken cancellationToken) =>
new ValueTask<Stream>(new GcsWriteStream(_fs, GetObjectName()));
/// <inheritdoc />
protected override async ValueTask WriteCoreAsync(Stream stream, bool overwrite, CancellationToken cancellationToken)
{
var obj = new global::Google.Apis.Storage.v1.Data.Object
{
Bucket = _fs.BucketName,
Name = GetObjectName()
};
var options = new UploadObjectOptions();
if (!overwrite)
options.IfGenerationMatch = 0;
await _fs.StorageClient
.UploadObjectAsync(obj, stream, options, cancellationToken)
.ConfigureAwait(false);
}
/// <inheritdoc />
protected override async ValueTask DeleteCoreAsync(CancellationToken cancellationToken)
{
try
{
await _fs.StorageClient
.DeleteObjectAsync(_fs.BucketName, GetObjectName(), cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
catch (GoogleApiException e) when (e.HttpStatusCode == HttpStatusCode.NotFound)
{
// Object doesn't exist, which is fine for this operation
}
}
/// <inheritdoc />
protected override ValueTask CopyToCoreAsync(string destinationPath, bool overwrite, CancellationToken cancellationToken) =>
CopyObjectAsync(_fs.BucketName, GetObjectName(), _fs.BucketName, destinationPath[1..], overwrite, cancellationToken);
/// <inheritdoc />
protected override ValueTask CopyToCoreAsync(VirtualFile destination, bool overwrite, CancellationToken cancellationToken)
{
if (destination is GcsFile file)
return CopyObjectAsync(_fs.BucketName, GetObjectName(), file._fs.BucketName, file.GetObjectName(), overwrite, cancellationToken);
return base.CopyToCoreAsync(destination, overwrite, cancellationToken);
}
/// <summary>
/// Returns the object name associated with this file.
/// </summary>
/// <returns>
/// The object name used in Google Cloud Storage.
/// </returns>
internal string GetObjectName() =>
_objectName ??= FullName[1..];
/// <summary>
/// Asynchronously copies a source object to the specified destination.
/// </summary>
/// <param name="sourceBucket">The name of the source GCS bucket.</param>
/// <param name="sourceObjectName">The source object name.</param>
/// <param name="destinationBucket">The name of the destination GCS bucket.</param>
/// <param name="destinationObjectName">The destination object name.</param>
/// <param name="overwrite">A boolean value indicating whether to overwrite the destination object 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 CopyObjectAsync(string sourceBucket, string sourceObjectName, string destinationBucket, string destinationObjectName, bool overwrite, CancellationToken cancellationToken)
{
if (sourceBucket == destinationBucket && sourceObjectName == destinationObjectName)
throw new IOException($"Cannot copy a file '{FullName}' to itself.");
var options = new CopyObjectOptions();
if (!overwrite)
options.IfGenerationMatch = 0;
await _fs.StorageClient
.CopyObjectAsync(sourceBucket, sourceObjectName, destinationBucket, destinationObjectName, options, cancellationToken)
.ConfigureAwait(false);
}
}