-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f2fa22f
commit a74ceb8
Showing
189 changed files
with
35,690 additions
and
35,882 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,56 @@ | ||
namespace Ecng.Backup.Amazon | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
namespace Ecng.Backup.Amazon; | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
using global::Amazon; | ||
|
||
using global::Amazon; | ||
using Ecng.Common; | ||
|
||
using Ecng.Common; | ||
/// <summary> | ||
/// Extension class for AWS. | ||
/// </summary> | ||
[CLSCompliant(false)] | ||
public static class AmazonExtensions | ||
{ | ||
private static RegionEndpoint[] _endpoints; | ||
|
||
/// <summary> | ||
/// Extension class for AWS. | ||
/// All regions. | ||
/// </summary> | ||
[CLSCompliant(false)] | ||
public static class AmazonExtensions | ||
public static IEnumerable<RegionEndpoint> Endpoints | ||
{ | ||
private static RegionEndpoint[] _endpoints; | ||
|
||
/// <summary> | ||
/// All regions. | ||
/// </summary> | ||
public static IEnumerable<RegionEndpoint> Endpoints | ||
get | ||
{ | ||
get | ||
lock (typeof(AmazonExtensions)) | ||
{ | ||
lock (typeof(AmazonExtensions)) | ||
{ | ||
_endpoints ??= [.. typeof(RegionEndpoint) | ||
.GetFields(BindingFlags.Static | BindingFlags.Public) | ||
.Where(f => f.FieldType == typeof(RegionEndpoint)) | ||
.Select(f => (RegionEndpoint)f.GetValue(null))]; | ||
} | ||
|
||
return _endpoints; | ||
_endpoints ??= [.. typeof(RegionEndpoint) | ||
.GetFields(BindingFlags.Static | BindingFlags.Public) | ||
.Where(f => f.FieldType == typeof(RegionEndpoint)) | ||
.Select(f => (RegionEndpoint)f.GetValue(null))]; | ||
} | ||
|
||
return _endpoints; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Get region by name. | ||
/// </summary> | ||
/// <param name="name">Region name.</param> | ||
/// <returns>Region.</returns> | ||
public static RegionEndpoint GetEndpoint(string name) | ||
{ | ||
if (name.IsEmpty()) | ||
throw new ArgumentNullException(nameof(name)); | ||
/// <summary> | ||
/// Get region by name. | ||
/// </summary> | ||
/// <param name="name">Region name.</param> | ||
/// <returns>Region.</returns> | ||
public static RegionEndpoint GetEndpoint(string name) | ||
{ | ||
if (name.IsEmpty()) | ||
throw new ArgumentNullException(nameof(name)); | ||
|
||
var region = Endpoints.FirstOrDefault(e => | ||
e.SystemName.EqualsIgnoreCase(name) || | ||
e.SystemName.Remove("-").EqualsIgnoreCase(name) || | ||
e.DisplayName.EqualsIgnoreCase(name)); | ||
var region = Endpoints.FirstOrDefault(e => | ||
e.SystemName.EqualsIgnoreCase(name) || | ||
e.SystemName.Remove("-").EqualsIgnoreCase(name) || | ||
e.DisplayName.EqualsIgnoreCase(name)); | ||
|
||
return region ?? RegionEndpoint.GetBySystemName(name); | ||
} | ||
return region ?? RegionEndpoint.GetBySystemName(name); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,144 +1,143 @@ | ||
namespace Ecng.Backup.Amazon | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
namespace Ecng.Backup.Amazon; | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
using global::Amazon; | ||
using global::Amazon.Runtime; | ||
using global::Amazon.Glacier.Model; | ||
using global::Amazon.Glacier; | ||
using global::Amazon; | ||
using global::Amazon.Runtime; | ||
using global::Amazon.Glacier.Model; | ||
using global::Amazon.Glacier; | ||
|
||
using Ecng.Common; | ||
using Ecng.Common; | ||
|
||
/// <summary> | ||
/// The data storage service based on Amazon Glacier https://aws.amazon.com/s3/glacier/ . | ||
/// </summary> | ||
public class AmazonGlacierService : Disposable, IBackupService | ||
{ | ||
private readonly IAmazonGlacier _client; | ||
private readonly string _vaultName; | ||
private readonly AWSCredentials _credentials; | ||
private readonly RegionEndpoint _endpoint; | ||
private const int _bufferSize = FileSizes.MB * 100; | ||
|
||
/// <summary> | ||
/// The data storage service based on Amazon Glacier https://aws.amazon.com/s3/glacier/ . | ||
/// Initializes a new instance of the <see cref="AmazonGlacierService"/>. | ||
/// </summary> | ||
public class AmazonGlacierService : Disposable, IBackupService | ||
/// <param name="endpoint">Region address.</param> | ||
/// <param name="bucket">Storage name.</param> | ||
/// <param name="accessKey">Key.</param> | ||
/// <param name="secretKey">Secret.</param> | ||
public AmazonGlacierService(string endpoint, string bucket, string accessKey, string secretKey) | ||
: this(AmazonExtensions.GetEndpoint(endpoint), bucket, accessKey, secretKey) | ||
{ | ||
private readonly IAmazonGlacier _client; | ||
private readonly string _vaultName; | ||
private readonly AWSCredentials _credentials; | ||
private readonly RegionEndpoint _endpoint; | ||
private const int _bufferSize = FileSizes.MB * 100; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="AmazonGlacierService"/>. | ||
/// </summary> | ||
/// <param name="endpoint">Region address.</param> | ||
/// <param name="bucket">Storage name.</param> | ||
/// <param name="accessKey">Key.</param> | ||
/// <param name="secretKey">Secret.</param> | ||
public AmazonGlacierService(string endpoint, string bucket, string accessKey, string secretKey) | ||
: this(AmazonExtensions.GetEndpoint(endpoint), bucket, accessKey, secretKey) | ||
{ | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="AmazonGlacierService"/>. | ||
/// </summary> | ||
/// <param name="endpoint">Region address.</param> | ||
/// <param name="vaultName">Storage name.</param> | ||
/// <param name="accessKey">Key.</param> | ||
/// <param name="secretKey">Secret.</param> | ||
[CLSCompliant(false)] | ||
public AmazonGlacierService(RegionEndpoint endpoint, string vaultName, string accessKey, string secretKey) | ||
{ | ||
_credentials = new BasicAWSCredentials(accessKey, secretKey); | ||
_endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); | ||
_vaultName = vaultName.ThrowIfEmpty(nameof(vaultName)); | ||
_client = new AmazonGlacierClient(_credentials, _endpoint); | ||
} | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="AmazonGlacierService"/>. | ||
/// </summary> | ||
/// <param name="endpoint">Region address.</param> | ||
/// <param name="vaultName">Storage name.</param> | ||
/// <param name="accessKey">Key.</param> | ||
/// <param name="secretKey">Secret.</param> | ||
[CLSCompliant(false)] | ||
public AmazonGlacierService(RegionEndpoint endpoint, string vaultName, string accessKey, string secretKey) | ||
{ | ||
_credentials = new BasicAWSCredentials(accessKey, secretKey); | ||
_endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); | ||
_vaultName = vaultName.ThrowIfEmpty(nameof(vaultName)); | ||
_client = new AmazonGlacierClient(_credentials, _endpoint); | ||
} | ||
|
||
bool IBackupService.CanFolders => false; | ||
bool IBackupService.CanPublish => false; | ||
bool IBackupService.CanPartialDownload => true; | ||
bool IBackupService.CanFolders => false; | ||
bool IBackupService.CanPublish => false; | ||
bool IBackupService.CanPartialDownload => true; | ||
|
||
IAsyncEnumerable<BackupEntry> IBackupService.FindAsync(BackupEntry parent, string criteria, CancellationToken cancellationToken) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
IAsyncEnumerable<BackupEntry> IBackupService.FindAsync(BackupEntry parent, string criteria, CancellationToken cancellationToken) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
Task IBackupService.DeleteAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> _client.DeleteArchiveAsync(new() | ||
{ | ||
VaultName = _vaultName, | ||
ArchiveId = entry.Name, | ||
}, cancellationToken); | ||
Task IBackupService.DeleteAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> _client.DeleteArchiveAsync(new() | ||
{ | ||
VaultName = _vaultName, | ||
ArchiveId = entry.Name, | ||
}, cancellationToken); | ||
|
||
Task IBackupService.FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotImplementedException(); | ||
Task IBackupService.FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotImplementedException(); | ||
|
||
async Task IBackupService.DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action<int> progress, CancellationToken cancellationToken) | ||
async Task IBackupService.DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action<int> progress, CancellationToken cancellationToken) | ||
{ | ||
GetJobOutputRequest request = new() | ||
{ | ||
GetJobOutputRequest request = new() | ||
{ | ||
//JobId = jobId, | ||
VaultName = _vaultName, | ||
}; | ||
//JobId = jobId, | ||
VaultName = _vaultName, | ||
}; | ||
|
||
if (offset != null || length != null) | ||
{ | ||
if (offset is null || length is null) | ||
throw new NotSupportedException(); | ||
if (offset != null || length != null) | ||
{ | ||
if (offset is null || length is null) | ||
throw new NotSupportedException(); | ||
|
||
request.Range = $"bytes={offset}-{offset + length}"; | ||
} | ||
request.Range = $"bytes={offset}-{offset + length}"; | ||
} | ||
|
||
var response = await _client.GetJobOutputAsync(request, cancellationToken); | ||
var response = await _client.GetJobOutputAsync(request, cancellationToken); | ||
|
||
using var webStream = response.Body; | ||
using var webStream = response.Body; | ||
|
||
var bytes = new byte[_bufferSize]; | ||
var readTotal = 0L; | ||
var bytes = new byte[_bufferSize]; | ||
var readTotal = 0L; | ||
|
||
var prevProgress = -1; | ||
var prevProgress = -1; | ||
|
||
var objLen = 0L; //TODO | ||
var objLen = 0L; //TODO | ||
|
||
while (readTotal < objLen) | ||
{ | ||
var expected = (int)(objLen - readTotal).Min(_bufferSize); | ||
var actual = await webStream.ReadAsync(bytes, 0, expected, cancellationToken); | ||
while (readTotal < objLen) | ||
{ | ||
var expected = (int)(objLen - readTotal).Min(_bufferSize); | ||
var actual = await webStream.ReadAsync(bytes, 0, expected, cancellationToken); | ||
|
||
if (actual == 0) | ||
break; | ||
if (actual == 0) | ||
break; | ||
|
||
await stream.WriteAsync(bytes, 0, actual, cancellationToken); | ||
await stream.WriteAsync(bytes, 0, actual, cancellationToken); | ||
|
||
readTotal += actual; | ||
readTotal += actual; | ||
|
||
var currProgress = (int)(readTotal * 100L / objLen); | ||
var currProgress = (int)(readTotal * 100L / objLen); | ||
|
||
if (currProgress < 100 && prevProgress < currProgress) | ||
{ | ||
progress(currProgress); | ||
prevProgress = currProgress; | ||
} | ||
if (currProgress < 100 && prevProgress < currProgress) | ||
{ | ||
progress(currProgress); | ||
prevProgress = currProgress; | ||
} | ||
} | ||
} | ||
|
||
Task IBackupService.UploadAsync(BackupEntry entry, Stream stream, Action<int> progress, CancellationToken cancellationToken) | ||
=> throw new NotImplementedException(); | ||
Task IBackupService.UploadAsync(BackupEntry entry, Stream stream, Action<int> progress, CancellationToken cancellationToken) | ||
=> throw new NotImplementedException(); | ||
|
||
Task<string> IBackupService.PublishAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotSupportedException(); | ||
Task<string> IBackupService.PublishAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotSupportedException(); | ||
|
||
Task IBackupService.UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotSupportedException(); | ||
Task IBackupService.UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotSupportedException(); | ||
|
||
Task IBackupService.CreateFolder(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotSupportedException(); | ||
Task IBackupService.CreateFolder(BackupEntry entry, CancellationToken cancellationToken) | ||
=> throw new NotSupportedException(); | ||
|
||
/// <summary> | ||
/// Disposes the managed resources. | ||
/// </summary> | ||
protected override void DisposeManaged() | ||
{ | ||
_client.Dispose(); | ||
base.DisposeManaged(); | ||
} | ||
/// <summary> | ||
/// Disposes the managed resources. | ||
/// </summary> | ||
protected override void DisposeManaged() | ||
{ | ||
_client.Dispose(); | ||
base.DisposeManaged(); | ||
} | ||
} |
Oops, something went wrong.