diff options
author | TopperDEL <github_com@tparth.de> | 2021-05-03 10:50:29 +0300 |
---|---|---|
committer | TopperDEL <github_com@tparth.de> | 2021-05-03 10:50:29 +0300 |
commit | a3d9d4c6ba7fa47fbb64491a93632ae5a262291a (patch) | |
tree | d2f869582e2ec7ce3dce33995a93c27c97948690 /Duplicati/Library/Backend/Storj | |
parent | b88a9fb6dcdacf3530a81503b411d47c841e9609 (diff) |
feat: Rename C# and Project-files to Storj
Diffstat (limited to 'Duplicati/Library/Backend/Storj')
-rw-r--r-- | Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj | 128 | ||||
-rw-r--r-- | Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs | 36 | ||||
-rw-r--r-- | Duplicati/Library/Backend/Storj/StorjBackend.cs | 359 | ||||
-rw-r--r-- | Duplicati/Library/Backend/Storj/StorjConfig.cs | 68 | ||||
-rw-r--r-- | Duplicati/Library/Backend/Storj/StorjFile.cs | 56 | ||||
-rw-r--r-- | Duplicati/Library/Backend/Storj/Strings.cs | 33 | ||||
-rw-r--r-- | Duplicati/Library/Backend/Storj/libstorj_uplink.dylib | bin | 0 -> 14341776 bytes | |||
-rw-r--r-- | Duplicati/Library/Backend/Storj/libstorj_uplink.so | bin | 0 -> 15439776 bytes | |||
-rw-r--r-- | Duplicati/Library/Backend/Storj/packages.config | 13 | ||||
-rw-r--r-- | Duplicati/Library/Backend/Storj/win-x64/storj_uplink.dll | bin | 0 -> 9595904 bytes | |||
-rw-r--r-- | Duplicati/Library/Backend/Storj/win-x86/storj_uplink.dll | bin | 0 -> 8198656 bytes |
11 files changed, 693 insertions, 0 deletions
diff --git a/Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj b/Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj new file mode 100644 index 000000000..c44e61a61 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/Duplicati.Library.Backend.Storj.csproj @@ -0,0 +1,128 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{AE035E01-C917-4F13-A35E-78F21C1A2F17}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Duplicati.Library.Backend.Tardigrade</RootNamespace> + <AssemblyName>Duplicati.Library.Backend.Tardigrade</AssemblyName> + <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <Deterministic>true</Deterministic> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> + <TargetFrameworkProfile /> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <PlatformTarget>x64</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="SQLite-net, Version=1.7.335.0, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\sqlite-net-pcl.1.7.335\lib\netstandard2.0\SQLite-net.dll</HintPath> + </Reference> + <Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.3.851, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath> + </Reference> + <Reference Include="SQLitePCLRaw.core, Version=2.0.3.851, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\SQLitePCLRaw.core.2.0.3\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath> + </Reference> + <Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.3.851, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\SQLitePCLRaw.bundle_green.2.0.3\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath> + </Reference> + <Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.3.851, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.3\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath> + </Reference> + <Reference Include="System.Core" /> + <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath> + </Reference> + <Reference Include="System.Numerics" /> + <Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath> + </Reference> + <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath> + </Reference> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + <Reference Include="uplink.NET, Version=2.6.0.0, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\..\packages\uplink.NET.2.6.1451\lib\netstandard2.0\uplink.NET.dll</HintPath> + </Reference> + </ItemGroup> + <ItemGroup> + <Compile Include="StorjFile.cs" /> + <Compile Include="Strings.cs" /> + <Compile Include="StorjBackend.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="StorjConfig.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj"> + <Project>{d63e53e4-a458-4c2f-914d-92f715f58acf}</Project> + <Name>Duplicati.Library.Common</Name> + </ProjectReference> + <ProjectReference Include="..\..\Interface\Duplicati.Library.Interface.csproj"> + <Project>{c5899f45-b0ff-483c-9d38-24a9fcaab237}</Project> + <Name>Duplicati.Library.Interface</Name> + </ProjectReference> + <ProjectReference Include="..\..\Localization\Duplicati.Library.Localization.csproj"> + <Project>{b68f2214-951f-4f78-8488-66e1ed3f50bf}</Project> + <Name>Duplicati.Library.Localization</Name> + </ProjectReference> + <ProjectReference Include="..\..\Utility\Duplicati.Library.Utility.csproj"> + <Project>{de3e5d4c-51ab-4e5e-bee8-e636cebfba65}</Project> + <Name>Duplicati.Library.Utility</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <None Include="libstorj_uplink.dylib"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="libstorj_uplink.so"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <Content Include="win-x64\storj_uplink.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + <Content Include="win-x86\storj_uplink.dll"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" /> + </Target> + <Import Project="..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\..\..\..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.3\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" /> +</Project>
\ No newline at end of file diff --git a/Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs b/Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..5f3cc907e --- /dev/null +++ b/Duplicati/Library/Backend/Storj/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("Duplicati.Library.Backend.Tardigrade")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Duplicati.Library.Backend.Tardigrade")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("ae035e01-c917-4f13-a35e-78f21c1a2f17")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Duplicati/Library/Backend/Storj/StorjBackend.cs b/Duplicati/Library/Backend/Storj/StorjBackend.cs new file mode 100644 index 000000000..7575525e3 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/StorjBackend.cs @@ -0,0 +1,359 @@ +using Duplicati.Library.Interface; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using uplink.NET.Interfaces; +using uplink.NET.Models; +using uplink.NET.Services; + +namespace Duplicati.Library.Backend.Tardigrade +{ + public class Tardigrade : IStreamingBackend + { + private const string TARDIGRADE_AUTH_METHOD = "tardigrade-auth-method"; + private const string TARDIGRADE_SATELLITE = "tardigrade-satellite"; + private const string TARDIGRADE_API_KEY = "tardigrade-api-key"; + private const string TARDIGRADE_SECRET = "tardigrade-secret"; + 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", "us1.storj.io:7777" }, + { "Asia East", "ap1.storj.io:7777" }, + { "Europe", "eu1.storj.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; + } + + // ReSharper disable once UnusedMember.Global + // This constructor is needed by the BackendLoader. + public Tardigrade() + { + } + + // ReSharper disable once UnusedMember.Global + // This constructor is needed by the BackendLoader. + public Tardigrade(string url, Dictionary<string, string> 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 + { + get { return Strings.Storj.DisplayName; } + } + + public string ProtocolKey => PROTOCOL_KEY; + + public IList<ICommandLineArgument> SupportedCommands + { + get + { + return new List<ICommandLineArgument>(new ICommandLineArgument[] { + new CommandLineArgument(TARDIGRADE_AUTH_METHOD, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAuthMethodDescriptionShort, Strings.Storj.StorjAuthMethodDescriptionLong, "API key"), + new CommandLineArgument(TARDIGRADE_SATELLITE, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSatelliteDescriptionShort, Strings.Storj.StorjSatelliteDescriptionLong, "us1.storj.io:7777"), + new CommandLineArgument(TARDIGRADE_API_KEY, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjAPIKeyDescriptionShort, Strings.Storj.StorjAPIKeyDescriptionLong), + new CommandLineArgument(TARDIGRADE_SECRET, CommandLineArgument.ArgumentType.Password, Strings.Storj.StorjSecretDescriptionShort, Strings.Storj.StorjSecretDescriptionLong), + new CommandLineArgument(TARDIGRADE_SHARED_ACCESS, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjSharedAccessDescriptionShort, Strings.Storj.StorjSharedAccessDescriptionLong), + new CommandLineArgument(TARDIGRADE_BUCKET, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjBucketDescriptionShort, Strings.Storj.StorjBucketDescriptionLong), + new CommandLineArgument(TARDIGRADE_FOLDER, CommandLineArgument.ArgumentType.String, Strings.Storj.StorjFolderDescriptionShort, Strings.Storj.StorjFolderDescriptionLong), + }); + } + } + + public string Description + { + get + { + return Strings.Storj.Description; + } + } + + public string[] DNSName + { + get + { + return new string[0]; + } + } + + public void CreateFolder() + { + //Storj DCS 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<StorjFile> files = new List<StorjFile>(); + 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) + { + StorjFile file = new StorjFile(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 = StorjFile.TARDIGRADE_LAST_ACCESS, Value = DateTime.Now.ToUniversalTime().ToString("O") }); + custom.Entries.Add(new CustomMetadataEntry { Key = StorjFile.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.Storj.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; + } + } +} diff --git a/Duplicati/Library/Backend/Storj/StorjConfig.cs b/Duplicati/Library/Backend/Storj/StorjConfig.cs new file mode 100644 index 000000000..d0280a5c8 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/StorjConfig.cs @@ -0,0 +1,68 @@ +using Duplicati.Library.Interface; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Duplicati.Library.Backend.Tardigrade +{ + public class StorjConfig : IWebModule + { + private const ConfigType DEFAULT_CONFIG_TYPE = ConfigType.Satellites; + private const string KEY_CONFIGTYPE = "tardigrade-config"; + private static readonly string DEFAULT_CONFIG_TYPE_STR = Enum.GetName(typeof(ConfigType), DEFAULT_CONFIG_TYPE); + + public enum ConfigType + { + Satellites, + AuthenticationMethods + } + + #region IWebModule implementation + + public string Key { get { return "tardigrade-getconfig"; } } + + public string DisplayName { get { return "Storj DCS configuration module"; } } + + public string Description { get { return "Exposes Storj DCS configuration as a web module"; } } + + public IList<ICommandLineArgument> SupportedCommands + { + get + { + return new List<ICommandLineArgument>(new ICommandLineArgument[] { + new CommandLineArgument(KEY_CONFIGTYPE, CommandLineArgument.ArgumentType.Enumeration, "The config to get", "Provides different config values", DEFAULT_CONFIG_TYPE_STR, Enum.GetNames(typeof(ConfigType))) + + }); + } + } + + public IDictionary<string, string> Execute(IDictionary<string, string> options) + { + string k; + options.TryGetValue(KEY_CONFIGTYPE, out k); + if (string.IsNullOrWhiteSpace(k)) + { + k = DEFAULT_CONFIG_TYPE_STR; + } + + ConfigType ct; + if (!Enum.TryParse<ConfigType>(k, true, out ct)) + { + ct = DEFAULT_CONFIG_TYPE; + } + + switch (ct) + { + case ConfigType.Satellites: + return Tardigrade.KNOWN_TARDIGRADE_SATELLITES; + case ConfigType.AuthenticationMethods: + return Tardigrade.KNOWN_AUTHENTICATION_METHODS; + default: + return Tardigrade.KNOWN_TARDIGRADE_SATELLITES; + } + } + #endregion + } +} diff --git a/Duplicati/Library/Backend/Storj/StorjFile.cs b/Duplicati/Library/Backend/Storj/StorjFile.cs new file mode 100644 index 000000000..7815f6c56 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/StorjFile.cs @@ -0,0 +1,56 @@ +using Duplicati.Library.Interface; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Duplicati.Library.Backend.Tardigrade +{ + public class StorjFile : IFileEntry + { + public static readonly string TARDIGRADE_LAST_ACCESS = "DUPLICATI:LAST-ACCESS"; + public static readonly string TARDIGRADE_LAST_MODIFICATION = "DUPLICATI:LAST-MODIFICATION"; + public bool IsFolder { get; set; } + + public DateTime LastAccess { get; set; } + + public DateTime LastModification { get; set; } + + public string Name { get; set; } + + public long Size { get; set; } + + public StorjFile() + { + + } + + public StorjFile(uplink.NET.Models.Object tardigradeObject) + { + IsFolder = tardigradeObject.IsPrefix; + var lastAccess = tardigradeObject.CustomMetaData.Entries.Where(e => e.Key == TARDIGRADE_LAST_ACCESS).FirstOrDefault(); + if (lastAccess != null && !string.IsNullOrEmpty(lastAccess.Value)) + { + LastAccess = DateTime.Parse(lastAccess.Value); + } + else + { + LastAccess = DateTime.MinValue; + } + + var lastMod = tardigradeObject.CustomMetaData.Entries.Where(e => e.Key == TARDIGRADE_LAST_MODIFICATION).FirstOrDefault(); + if (lastMod != null && !string.IsNullOrEmpty(lastMod.Value)) + { + LastModification = DateTime.Parse(lastMod.Value); + } + else + { + LastModification = DateTime.MinValue; + } + + Name = tardigradeObject.Key; + Size = tardigradeObject.SystemMetaData.ContentLength; + } + } +} diff --git a/Duplicati/Library/Backend/Storj/Strings.cs b/Duplicati/Library/Backend/Storj/Strings.cs new file mode 100644 index 000000000..51b445067 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/Strings.cs @@ -0,0 +1,33 @@ +using Duplicati.Library.Localization.Short; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Duplicati.Library.Backend.Strings +{ + internal static class Storj + { + public static string DisplayName { get { return LC.L(@"Storj DCS (Decentralized Cloud Storage)"); } } + public static string Description { get { return LC.L(@"This backend can read and write data to the Storj DCS."); } } + public static string TestConnectionFailed { get { return LC.L(@"The connection-test failed."); } } + public static string StorjAuthMethodDescriptionShort { get { return LC.L(@"The authentication method"); } } + public static string StorjAuthMethodDescriptionLong { get { return LC.L(@"The authentication method describes which way to use to connect to the network - either via API key or via an access grant."); } } + public static string StorjSatelliteDescriptionShort { get { return LC.L(@"The satellite"); } } + public static string StorjSatelliteDescriptionLong { get { return LC.L(@"The satellite that keeps track of all metadata. Use a Storj DCS server for high-performance SLA-backed connectivity or use a community server. Or even host your own."); } } + public static string StorjAPIKeyDescriptionShort { get { return LC.L(@"The API key"); } } + public static string StorjAPIKeyDescriptionLong { get { return LC.L(@"The API key grants access to a specific project on your chosen satellite. Head over to the dashboard of your satellite to create one if you do not already have an API key."); } } + public static string StorjSecretDescriptionShort { get { return LC.L(@"The encryption passphrase"); } } + public static string StorjSecretDescriptionLong { get { return LC.L(@"The encryption passphrase is used to encrypt your data before sending it to the Storj network. This passphrase can be the only secret to provide - for Storj you do not necessary need any additional encryption (from Duplicati) in place."); } } + public static string StorjSecretVerifyDescriptionShort { get { return LC.L(@"The encryption passphrase (for verification)"); } } + public static string StorjSecretVerifyDescriptionLong { get { return LC.L(@"The encryption passphrase verification to make sure you provided the expected value."); } } + public static string StorjSharedAccessDescriptionShort { get { return LC.L(@"The access grant"); } } + public static string StorjSharedAccessDescriptionLong { get { return LC.L(@"An access grant contains all information in one encrypted string. You may use it instead of a satellite, API key and secret."); } } + public static string StorjBucketDescriptionShort { get { return LC.L(@"The bucket"); } } + public static string StorjBucketDescriptionLong { get { return LC.L(@"The bucket where the backup will reside in."); } } + public static string StorjFolderDescriptionShort { get { return LC.L(@"The folder"); } } + public static string StorjFolderDescriptionLong { get { return LC.L(@"The folder within the bucket where the backup will reside in."); } } + public static string StorjEncryptionPassphrasesDoNotMatchError { get { return LC.L(@"The encryption passphrases do not match"); } } + } +} diff --git a/Duplicati/Library/Backend/Storj/libstorj_uplink.dylib b/Duplicati/Library/Backend/Storj/libstorj_uplink.dylib Binary files differnew file mode 100644 index 000000000..a3e4de942 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/libstorj_uplink.dylib diff --git a/Duplicati/Library/Backend/Storj/libstorj_uplink.so b/Duplicati/Library/Backend/Storj/libstorj_uplink.so Binary files differnew file mode 100644 index 000000000..0ecab8ba8 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/libstorj_uplink.so diff --git a/Duplicati/Library/Backend/Storj/packages.config b/Duplicati/Library/Backend/Storj/packages.config new file mode 100644 index 000000000..1592ab1f8 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/packages.config @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="sqlite-net-pcl" version="1.7.335" targetFramework="net471" /> + <package id="SQLitePCLRaw.bundle_green" version="2.0.3" targetFramework="net471" /> + <package id="SQLitePCLRaw.core" version="2.0.3" targetFramework="net471" /> + <package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.3" targetFramework="net471" /> + <package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.3" targetFramework="net471" /> + <package id="System.Buffers" version="4.4.0" targetFramework="net471" /> + <package id="System.Memory" version="4.5.3" targetFramework="net471" /> + <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net471" /> + <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net471" /> + <package id="uplink.NET" version="2.6.1451" targetFramework="net471" /> +</packages>
\ No newline at end of file diff --git a/Duplicati/Library/Backend/Storj/win-x64/storj_uplink.dll b/Duplicati/Library/Backend/Storj/win-x64/storj_uplink.dll Binary files differnew file mode 100644 index 000000000..8b42a9c6b --- /dev/null +++ b/Duplicati/Library/Backend/Storj/win-x64/storj_uplink.dll diff --git a/Duplicati/Library/Backend/Storj/win-x86/storj_uplink.dll b/Duplicati/Library/Backend/Storj/win-x86/storj_uplink.dll Binary files differnew file mode 100644 index 000000000..c34a75d19 --- /dev/null +++ b/Duplicati/Library/Backend/Storj/win-x86/storj_uplink.dll |