diff options
Diffstat (limited to 'Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs')
-rw-r--r-- | Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs | 327 |
1 files changed, 23 insertions, 304 deletions
diff --git a/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs b/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs index 0bf808105..255830500 100644 --- a/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs +++ b/Duplicati/Library/Backend/Tardigrade/TardigradeBackend.cs @@ -14,7 +14,15 @@ using uplink.NET.Services; namespace Duplicati.Library.Backend.Tardigrade { - public class Tardigrade : IStreamingBackend + + /// <summary> + /// This backend is deprecated! It will be removed in the future. + /// Tardigrade renamed to Storj DCS in Spring 2021 - but existing Tardigrade-Configurations could not be easily renamed. + /// So we decided to "copy" Tardigrade over to the new name Storj DCS. In order to reduce duplicate code, the old + /// Tardigrade-Backend hands it's logic over to Storj DCS. Only the UI-specific part, the config-parameters and + /// the protocol-key stay here named for Tardigrade. + /// </summary> + public class Tardigrade : Duplicati.Library.Backend.Storj.Storj, IStreamingBackend { private const string TARDIGRADE_AUTH_METHOD = "tardigrade-auth-method"; private const string TARDIGRADE_SATELLITE = "tardigrade-satellite"; @@ -23,339 +31,50 @@ namespace Duplicati.Library.Backend.Tardigrade private const string TARDIGRADE_SHARED_ACCESS = "tardigrade-shared-access"; private const string TARDIGRADE_BUCKET = "tardigrade-bucket"; private const string TARDIGRADE_FOLDER = "tardigrade-folder"; - private const string PROTOCOL_KEY = "tardigrade"; - private const string TARDIGRADE_PARTNER_ID = "duplicati"; - - private readonly string _satellite; - private readonly string _api_key; - private readonly string _secret; - private readonly string _bucket; - private readonly string _folder; - private Access _access; - private IBucketService _bucketService; - private IObjectService _objectService; - - public static readonly Dictionary<string, string> KNOWN_TARDIGRADE_SATELLITES = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){ - { "US Central 1", "us-central-1.tardigrade.io:7777" }, - { "Asia East 1", "asia-east-1.tardigrade.io:7777" }, - { "Saltlake", "saltlake.tardigrade.io:7777" }, - { "Europe West 1", "europe-west-1.tardigrade.io:7777" }, - { "Europe North 1", "europe-north-1.tardigrade.io:7777" }, - }; - - public static readonly Dictionary<string, string> KNOWN_AUTHENTICATION_METHODS = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase){ - { "API key", "API key" }, - { "Access grant", "Access grant" }, - }; - - [DllImport("kernel32.dll")] - protected static extern IntPtr LoadLibrary(string filename); - - private static bool _libraryLoaded = false; - private static void InitStorjLibrary() - { - if (_libraryLoaded) - return; - if (Duplicati.Library.Common.Platform.IsClientWindows) //We need to init only on Windows to distinguish between x64 and x86 - { - if (System.Environment.Is64BitProcess) - { - var res = LoadLibrary("win-x64/storj_uplink.dll"); - } - else - { - var res = LoadLibrary("win-x86/storj_uplink.dll"); - } - } - Access.SetTempDirectory(Library.Utility.TempFolder.SystemTempPath); - _libraryLoaded = true; - } + private const string PROTOCOL_KEY = "tardigrade"; // ReSharper disable once UnusedMember.Global // This constructor is needed by the BackendLoader. - public Tardigrade() + public Tardigrade():base() { } // ReSharper disable once UnusedMember.Global // This constructor is needed by the BackendLoader. - public Tardigrade(string url, Dictionary<string, string> options) + public Tardigrade(string url, Dictionary<string, string> options) :base(url, options) { - InitStorjLibrary(); - - var auth_method = options[TARDIGRADE_AUTH_METHOD]; - if (auth_method == "Access grant") - { - //Create an access from the access grant - var shared_access = options[TARDIGRADE_SHARED_ACCESS]; - _access = new Access(shared_access, new Config() { UserAgent = TARDIGRADE_PARTNER_ID }); - } - else - { - //Create an access for a satellite, API key and encryption passphrase - _satellite = options[TARDIGRADE_SATELLITE]; - - if (options.ContainsKey(TARDIGRADE_API_KEY)) - { - _api_key = options[TARDIGRADE_API_KEY]; - } - if (options.ContainsKey(TARDIGRADE_SECRET)) - { - _secret = options[TARDIGRADE_SECRET]; - } - - _access = new Access(_satellite, _api_key, _secret, new Config() { UserAgent = TARDIGRADE_PARTNER_ID }); - } - - _bucketService = new BucketService(_access); - _objectService = new ObjectService(_access); - - //If no bucket was provided use the default "duplicati"-bucket - if (options.ContainsKey(TARDIGRADE_BUCKET)) - { - _bucket = options[TARDIGRADE_BUCKET]; - } - else - { - _bucket = "duplicati"; - } - - if (options.ContainsKey(TARDIGRADE_FOLDER)) - { - _folder = options[TARDIGRADE_FOLDER]; - } } - public string DisplayName + public new string DisplayName { get { return Strings.Tardigrade.DisplayName; } } - public string ProtocolKey => PROTOCOL_KEY; + public new string ProtocolKey => PROTOCOL_KEY; - public IList<ICommandLineArgument> SupportedCommands + public new IList<ICommandLineArgument> SupportedCommands { get { return new List<ICommandLineArgument>(new ICommandLineArgument[] { - new CommandLineArgument(TARDIGRADE_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeAuthMethodDescriptionShort, Strings.Tardigrade.TardigradeAuthMethodDescriptionLong, "API key"), - new CommandLineArgument(TARDIGRADE_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeSatelliteDescriptionShort, Strings.Tardigrade.TardigradeSatelliteDescriptionLong, "us-central-1.tardigrade.io:7777"), - new CommandLineArgument(TARDIGRADE_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeAPIKeyDescriptionShort, Strings.Tardigrade.TardigradeAPIKeyDescriptionLong), - new CommandLineArgument(TARDIGRADE_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Tardigrade.TardigradeSecretDescriptionShort, Strings.Tardigrade.TardigradeSecretDescriptionLong), - new CommandLineArgument(TARDIGRADE_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeSharedAccessDescriptionShort, Strings.Tardigrade.TardigradeSharedAccessDescriptionLong), - new CommandLineArgument(TARDIGRADE_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeBucketDescriptionShort, Strings.Tardigrade.TardigradeBucketDescriptionLong), - new CommandLineArgument(TARDIGRADE_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Tardigrade.TardigradeFolderDescriptionShort, Strings.Tardigrade.TardigradeFolderDescriptionLong), + new CommandLineArgument(TARDIGRADE_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAuthMethodDescriptionShort, Strings.Storj.StorjAuthMethodDescriptionLong, "API key", null, null), + new CommandLineArgument(TARDIGRADE_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSatelliteDescriptionShort, Strings.Storj.StorjSatelliteDescriptionLong, "us1.storj.io:7777", null, null), + new CommandLineArgument(TARDIGRADE_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAPIKeyDescriptionShort, Strings.Storj.StorjAPIKeyDescriptionLong, null, null, null), + new CommandLineArgument(TARDIGRADE_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Storj.StorjSecretDescriptionShort, Strings.Storj.StorjSecretDescriptionLong, null, null, null), + new CommandLineArgument(TARDIGRADE_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSharedAccessDescriptionShort, Strings.Storj.StorjSharedAccessDescriptionLong, null, null, null), + new CommandLineArgument(TARDIGRADE_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjBucketDescriptionShort, Strings.Storj.StorjBucketDescriptionLong, null, null, null), + new CommandLineArgument(TARDIGRADE_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjFolderDescriptionShort, Strings.Storj.StorjFolderDescriptionLong, null, null, null), }); } } - public string Description + public new string Description { get { return Strings.Tardigrade.Description; } } - - public string[] DNSName - { - get - { - return new string[0]; - } - } - - public void CreateFolder() - { - //Tardigrade has no folders - } - - public void Delete(string remotename) - { - var deleteTask = DeleteAsync(remotename); - deleteTask.Wait(); - } - - public async Task DeleteAsync(string remotename) - { - try - { - var bucket = await _bucketService.EnsureBucketAsync(_bucket); - await _objectService.DeleteObjectAsync(bucket, GetBasePath() + remotename); - } - catch (Exception root) - { - throw new FileMissingException(root); - } - } - - public void Dispose() - { - if (_objectService != null) - { - _objectService = null; - } - if (_bucketService != null) - { - _bucketService = null; - } - if (_access != null) - { - _access.Dispose(); - _access = null; - } - } - - public void Get(string remotename, string filename) - { - var getTask = GetAsync(remotename, filename); - getTask.Wait(); - } - - public async Task GetAsync(string remotename, string filename) - { - var bucket = await _bucketService.EnsureBucketAsync(_bucket); - var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false); - await download.StartDownloadAsync(); - - if (download.Completed) - { - using (FileStream file = new FileStream(filename, FileMode.Create)) - { - await file.WriteAsync(download.DownloadedBytes, 0, (int)download.BytesReceived); - await file.FlushAsync().ConfigureAwait(false); - } - } - } - - public void Get(string remotename, Stream stream) - { - var getTask = GetAsync(remotename, stream); - getTask.Wait(); - } - - public async Task GetAsync(string remotename, Stream stream) - { - int index = 0; - var bucket = await _bucketService.EnsureBucketAsync(_bucket); - var download = await _objectService.DownloadObjectAsync(bucket, GetBasePath() + remotename, new DownloadOptions(), false); - download.DownloadOperationProgressChanged += (op) => - { - int newPartLength = (int)op.BytesReceived - index; - byte[] newPart = new byte[newPartLength]; - Array.Copy(op.DownloadedBytes, index, newPart, 0, newPartLength); - stream.Write(newPart, 0, newPartLength); - index = index + newPartLength; - }; - await download.StartDownloadAsync(); - } - - public IEnumerable<IFileEntry> List() - { - var listTask = ListAsync(); - listTask.Wait(); - return listTask.Result; - } - - private async Task<IEnumerable<IFileEntry>> ListAsync() - { - List<TardigradeFile> files = new List<TardigradeFile>(); - var bucket = await _bucketService.EnsureBucketAsync(_bucket); - var prefix = GetBasePath(); - var objects = await _objectService.ListObjectsAsync(bucket, new ListObjectsOptions { Recursive = true, System = true, Custom = true, Prefix = prefix }); - - foreach (var obj in objects.Items) - { - TardigradeFile file = new TardigradeFile(obj); - if (prefix != "") - { - file.Name = file.Name.Replace(prefix, ""); - } - files.Add(file); - } - - return files; - } - - public async Task PutAsync(string remotename, string filename, CancellationToken cancelToken) - { - using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) - await PutAsync(remotename, fs, cancelToken); - } - - public async Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken) - { - var bucket = await _bucketService.EnsureBucketAsync(_bucket); - CustomMetadata custom = new CustomMetadata(); - custom.Entries.Add(new CustomMetadataEntry { Key = TardigradeFile.TARDIGRADE_LAST_ACCESS, Value = DateTime.Now.ToUniversalTime().ToString("O") }); - custom.Entries.Add(new CustomMetadataEntry { Key = TardigradeFile.TARDIGRADE_LAST_MODIFICATION, Value = DateTime.Now.ToUniversalTime().ToString("O") }); - var upload = await _objectService.UploadObjectAsync(bucket, GetBasePath() + remotename, new UploadOptions(), stream, custom, false); - await upload.StartUploadAsync(); - } - - public void Test() - { - var testTask = TestAsync(); - testTask.Wait(10000); - if (!testTask.Result) - { - throw new Exception(Strings.Tardigrade.TestConnectionFailed); - } - } - - /// <summary> - /// Test the connection by: - /// - creating the bucket (if it not already exists) - /// - uploading 256 random bytes to a test-file - /// - downloading the file back and expecting 256 bytes - /// </summary> - /// <returns>true, if the test was successfull or and exception</returns> - private async Task<bool> TestAsync() - { - string testFileName = GetBasePath() + "duplicati_test.dat"; - - var bucket = await _bucketService.EnsureBucketAsync(_bucket); - var upload = await _objectService.UploadObjectAsync(bucket, testFileName, new UploadOptions(), GetRandomBytes(256), false); - await upload.StartUploadAsync(); - - var download = await _objectService.DownloadObjectAsync(bucket, testFileName, new DownloadOptions(), false); - await download.StartDownloadAsync(); - - await _objectService.DeleteObjectAsync(bucket, testFileName); - - if (download.Failed || download.BytesReceived != 256) - { - throw new Exception(download.ErrorMessage); - } - - return true; - } - - /// <summary> - /// Gets the base path - depending on there is a folder set or not - /// </summary> - /// <returns>The base path within a bucket where the backup shall be placed</returns> - private string GetBasePath() - { - if (!string.IsNullOrEmpty(_folder)) - return _folder + "/"; - else - return ""; - } - - /// <summary> - /// Creates some random bytes with the given length - just for testing the connection - /// </summary> - /// <param name="length">The length of the bytes to create</param> - /// <returns>A byte-array with the given length</returns> - private static byte[] GetRandomBytes(long length) - { - byte[] bytes = new byte[length]; - Random rand = new Random(); - rand.NextBytes(bytes); - - return bytes; - } } } |