src/AlibabaCloud.OSS.V2/Client.Extensions.cs (182 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AlibabaCloud.OSS.V2.Internal;
namespace AlibabaCloud.OSS.V2
{
public partial class Client
{
/// <summary>
/// Checks if the object exists
/// </summary>
/// <param name="bucket">The request parameter to send.</param>
/// <param name="key">The request parameter to send.</param>
/// <param name="versionId">Optional, The version ID of the source object.</param>>
/// <param name="cancellationToken"><see cref="CancellationToken"/>Optional,The cancellation token to cancel.</param>
/// <returns>True if the object exists, else False.</returns>
public async Task<bool> IsObjectExistAsync(
string bucket,
string key,
string? versionId = null,
CancellationToken cancellationToken = default
)
{
try
{
await GetObjectMetaAsync(
new()
{
Bucket = bucket,
Key = key,
VersionId = versionId
},
null,
cancellationToken
);
return true;
}
catch (OperationException e)
{
if (e.InnerException is ServiceException se)
{
if (string.Equals(se.ErrorCode, "NoSuchKey"))
return false;
if (se.StatusCode == 404 &&
string.Equals(se.ErrorCode, "BadErrorResponse"))
return false;
}
throw;
}
}
/// <summary>
/// Checks if the bucket exists
/// </summary>
/// <param name="bucket">The request parameter to send.</param>
/// <param name="cancellationToken"><see cref="CancellationToken"/>Optional,The cancellation token to cancel.</param>
/// <returns>True if the object exists, else False.</returns>
public async Task<bool> IsBucketExistAsync(
string bucket,
CancellationToken cancellationToken = default
)
{
try
{
await GetBucketAclAsync(
new()
{
Bucket = bucket
},
null,
cancellationToken
);
return true;
}
catch (OperationException e)
{
if (e.InnerException is ServiceException se)
if (string.Equals(se.ErrorCode, "NoSuchBucket"))
return false;
throw;
}
}
/// <summary>
/// Put object from local file.
/// </summary>
/// <param name="request"><see cref="Models.PutObjectRequest"/>The request parameter to send.</param>
/// <param name="filepath">The file path name.</param>
/// <param name="options"><see cref="OperationOptions"/>Optional, operation options</param>
/// <param name="cancellationToken"><see cref="CancellationToken"/>Optional,The cancellation token to cancel operation.</param>
/// <returns><see cref="Models.PutObjectResult" />The result instance.</returns>
public async Task<Models.PutObjectResult> PutObjectFromFileAsync(
Models.PutObjectRequest request,
string filepath,
OperationOptions? options = null,
CancellationToken cancellationToken = default
)
{
#if NET5_0_OR_GREATER
await using var fs = File.Open(filepath, FileMode.Open);
#else
using var fs = File.Open(filepath, FileMode.Open);
#endif
request.Body = fs;
return await PutObjectAsync(request, options, cancellationToken);
}
/// <summary>
/// Get object to local file.
/// </summary>
/// <param name="request"><see cref="Models.GetObjectRequest"/>The request parameter to send.</param>
/// <param name="filepath">The file path name.</param>
/// <param name="options"><see cref="OperationOptions"/>Optional, operation options</param>
/// <param name="cancellationToken"><see cref="CancellationToken"/>Optional,The cancellation token to cancel operation.</param>
/// <returns><see cref="Models.GetObjectResult" />The result instance.</returns>
public async Task<Models.GetObjectResult> GetObjectToFileAsync(
Models.GetObjectRequest request,
string filepath,
OperationOptions? options = null,
CancellationToken cancellationToken = default
)
{
var (retry, readTimeout) = _clientImpl.GetRuntimeContext(options);
Models.GetObjectResult? result;
Exception? lastEx = null;
var i = 0;
WriteOnlyHashStream? crcTracker = null;
Stream? progTracker = null;
var trackers = new List<Stream>();
if (_clientImpl.Options.FeatureFlags.HasFlag(FeatureFlagsType.EnableCrc64CheckDownload))
{
crcTracker = new WriteOnlyHashStream(new HashCrc64(0));
trackers.Add(crcTracker);
}
do
{
result = await GetObjectAsync(request, options, cancellationToken).ConfigureAwait(false);
lastEx = null;
if (request.ProgressFn != null && progTracker == null)
{
progTracker = new ProgressStream(request.ProgressFn, result.ContentLength ?? -1);
trackers.Add(progTracker);
}
using var cts = new CancellationTokenSource(readTimeout);
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancellationToken);
try
{
using var fs = File.Open(filepath, FileMode.Create);
byte[] buffer = new byte[Defaults.DefaultCopyBufferSize];
int count;
while ((count = await result.Body!.ReadAsync(buffer, 0, buffer.Length, linkedCts.Token).ConfigureAwait(false)) != 0)
{
await fs.WriteAsync(buffer, 0, count, linkedCts.Token).ConfigureAwait(false);
foreach (var t in trackers)
{
t.Write(buffer, 0, count);
}
cts.CancelAfter(readTimeout);
}
if (crcTracker != null)
{
if (result.Headers.TryGetValue("x-oss-hash-crc64ecma", out var scrc))
{
var val = crcTracker.Hash.Final();
var ccrc = Convert.ToString(BitConverter.ToUInt64(val, 0), CultureInfo.InvariantCulture);
if (!string.Equals(ccrc, scrc))
{
result.Headers.TryGetValue("x-oss-request-id", out var requestId);
throw new InconsistentException(ccrc, scrc, requestId ?? "");
}
}
}
break;
}
catch (OperationCanceledException e)
{
lastEx = e;
if (cts.IsCancellationRequested)
{
lastEx = new RequestTimeoutException(
$"The operation was cancelled because it exceeded the configured timeout of {readTimeout:g}. ", e);
}
else if (cancellationToken.IsCancellationRequested)
{
break;
}
}
catch (Exception e)
{
lastEx = e;
}
finally
{
result.Body!.Dispose();
result.InnerBody = null;
if (lastEx != null)
{
foreach (var t in trackers)
{
t.Seek(0, SeekOrigin.Begin);
}
}
}
} while (++i < retry);
if (lastEx != null)
{
throw lastEx;
}
return result;
}
}
}