Remove support for Amazon Cloud Drive.
Amazon discontinued access to the Cloud Drive API. See https://forum.duplicati.com/t/amazon-cloud-drive-discontinued/7391.
This commit is contained in:
@@ -45,8 +45,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.A
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Localization", "Duplicati\Library\Localization\Duplicati.Library.Localization.csproj", "{B68F2214-951F-4F78-8488-66E1ED3F50BF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.AmazonCloudDrive", "Duplicati\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj", "{08D7E42D-285C-4010-9881-986125FE2F3E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.AutoUpdater", "Duplicati\Library\AutoUpdater\Duplicati.Library.AutoUpdater.csproj", "{7E119745-1F62-43F0-936C-F312A1912C0B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.SQLiteHelper", "Duplicati\Library\SQLiteHelper\Duplicati.Library.SQLiteHelper.csproj", "{2C838169-B187-4B09-8768-1C24C2521C8D}"
|
||||
@@ -179,10 +177,6 @@ Global
|
||||
{B68F2214-951F-4F78-8488-66E1ED3F50BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B68F2214-951F-4F78-8488-66E1ED3F50BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B68F2214-951F-4F78-8488-66E1ED3F50BF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7E119745-1F62-43F0-936C-F312A1912C0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7E119745-1F62-43F0-936C-F312A1912C0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7E119745-1F62-43F0-936C-F312A1912C0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -71,8 +71,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.H
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.CommandLine.RecoveryTool", "Duplicati\CommandLine\RecoveryTool\Duplicati.CommandLine.RecoveryTool.csproj", "{4A010589-76E6-4F05-A5C4-4598D5DF11F8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.AmazonCloudDrive", "Duplicati\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj", "{08D7E42D-285C-4010-9881-986125FE2F3E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Backblaze", "Duplicati\Library\Backend\Backblaze\Duplicati.Library.Backend.Backblaze.csproj", "{61C43D61-4368-4942-84A3-1EB623F4EF2A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Library.Backend.Mega", "Duplicati\Library\Backend\Mega\Duplicati.Library.Backend.Mega.csproj", "{6643A5AE-AB38-453F-ADCE-408E35A81A83}"
|
||||
@@ -245,10 +243,6 @@ Global
|
||||
{4A010589-76E6-4F05-A5C4-4598D5DF11F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4A010589-76E6-4F05-A5C4-4598D5DF11F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4A010589-76E6-4F05-A5C4-4598D5DF11F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08D7E42D-285C-4010-9881-986125FE2F3E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{61C43D61-4368-4942-84A3-1EB623F4EF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{61C43D61-4368-4942-84A3-1EB623F4EF2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{61C43D61-4368-4942-84A3-1EB623F4EF2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -126,10 +126,6 @@
|
||||
<Project>{D60AD540-0E7D-40CE-83AE-D26E01FFE9B8}</Project>
|
||||
<Name>Duplicati.Library.Backend.HubiC</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj">
|
||||
<Project>{08D7E42D-285C-4010-9881-986125FE2F3E}</Project>
|
||||
<Name>Duplicati.Library.Backend.AmazonCloudDrive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\CloudFiles\Duplicati.Library.Backend.CloudFiles.csproj">
|
||||
<Project>{1BFAE226-8364-4086-825C-BB83F6F3EE4C}</Project>
|
||||
<Name>Duplicati.Library.Backend.CloudFiles</Name>
|
||||
@@ -195,4 +191,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -132,10 +132,6 @@
|
||||
<Project>{D60AD540-0E7D-40CE-83AE-D26E01FFE9B8}</Project>
|
||||
<Name>Duplicati.Library.Backend.HubiC</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj">
|
||||
<Project>{08D7E42D-285C-4010-9881-986125FE2F3E}</Project>
|
||||
<Name>Duplicati.Library.Backend.AmazonCloudDrive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Backblaze\Duplicati.Library.Backend.Backblaze.csproj">
|
||||
<Project>{61C43D61-4368-4942-84A3-1EB623F4EF2A}</Project>
|
||||
<Name>Duplicati.Library.Backend.Backblaze</Name>
|
||||
@@ -160,4 +156,4 @@
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -203,10 +203,6 @@
|
||||
<Project>{4A010589-76E6-4F05-A5C4-4598D5DF11F8}</Project>
|
||||
<Name>Duplicati.CommandLine.RecoveryTool</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj">
|
||||
<Project>{08D7E42D-285C-4010-9881-986125FE2F3E}</Project>
|
||||
<Name>Duplicati.Library.Backend.AmazonCloudDrive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\Backblaze\Duplicati.Library.Backend.Backblaze.csproj">
|
||||
<Project>{61C43D61-4368-4942-84A3-1EB623F4EF2A}</Project>
|
||||
<Name>Duplicati.Library.Backend.Backblaze</Name>
|
||||
@@ -256,4 +252,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -157,10 +157,6 @@
|
||||
<Project>{10D2D1B7-C664-41D8-9B3A-00040C3D421B}</Project>
|
||||
<Name>Duplicati.Library.Main</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj">
|
||||
<Project>{08D7E42D-285C-4010-9881-986125FE2F3E}</Project>
|
||||
<Name>Duplicati.Library.Backend.AmazonCloudDrive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Backblaze\Duplicati.Library.Backend.Backblaze.csproj">
|
||||
<Project>{61C43D61-4368-4942-84A3-1EB623F4EF2A}</Project>
|
||||
<Name>Duplicati.Library.Backend.Backblaze</Name>
|
||||
@@ -193,4 +189,4 @@
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -313,10 +313,6 @@
|
||||
<Project>{4A010589-76E6-4F05-A5C4-4598D5DF11F8}</Project>
|
||||
<Name>Duplicati.CommandLine.RecoveryTool</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj">
|
||||
<Project>{08D7E42D-285C-4010-9881-986125FE2F3E}</Project>
|
||||
<Name>Duplicati.Library.Backend.AmazonCloudDrive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Library\Backend\Backblaze\Duplicati.Library.Backend.Backblaze.csproj">
|
||||
<Project>{61C43D61-4368-4942-84A3-1EB623F4EF2A}</Project>
|
||||
<Name>Duplicati.Library.Backend.Backblaze</Name>
|
||||
@@ -467,4 +463,4 @@ copy /Y '%USERPROFILE%\.nuget\packages\alphavss\1.4.0\lib\net45\AlphaVSS.*.dll'
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent></PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -1,678 +0,0 @@
|
||||
// Copyright (C) 2015, The Duplicati Team
|
||||
// http://www.duplicati.com, info@duplicati.com
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
using Duplicati.Library.Common.IO;
|
||||
using Duplicati.Library.Interface;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Duplicati.Library.Backend.AmazonCloudDrive
|
||||
{
|
||||
// ReSharper disable once ClassNeverInstantiated.Global
|
||||
// This class is instantiated dynamically in the BackendLoader.
|
||||
public class AmzCD : IBackend, IStreamingBackend, IRenameEnabledBackend
|
||||
{
|
||||
private const string AUTHID_OPTION = "authid";
|
||||
private const string LABELS_OPTION = "amzcd-labels";
|
||||
private const string DELAY_OPTION = "amzcd-consistency-delay";
|
||||
|
||||
private const string DEFAULT_LABELS = "duplicati,backup";
|
||||
private const string DEFAULT_DELAY = "30s";
|
||||
|
||||
private const int PAGE_SIZE = 200;
|
||||
|
||||
private const string CLOUDRIVE_MASTER_URL = "https://drive.amazonaws.com/drive/v1/account/endpoint";
|
||||
private const string CACHE_FILE_NAME_TEMPLATE = "dupl-amzcd-endp-{0}-cache.txt";
|
||||
private static readonly TimeSpan KEEP_CACHE_FILE_TIME = TimeSpan.FromDays(5);
|
||||
|
||||
private const string CONTENT_KIND_FOLDER = "FOLDER";
|
||||
private const string CONTENT_KIND_FILE = "FILE";
|
||||
|
||||
private EndpointInfo m_endPointInfo;
|
||||
private ResourceModel m_curdir;
|
||||
|
||||
private readonly string m_path;
|
||||
private readonly string[] m_labels;
|
||||
|
||||
private readonly string m_authid;
|
||||
private readonly OAuthHelper m_oauth;
|
||||
private Dictionary<string, string> m_filecache;
|
||||
private readonly string m_userid;
|
||||
private readonly TimeSpan m_delayTimeSpan;
|
||||
|
||||
private static readonly object m_waitUntilLock;
|
||||
private static readonly Dictionary<string, DateTime> m_waitUntilAuthId;
|
||||
private static Dictionary<string, DateTime> m_waitUntilRemotename;
|
||||
|
||||
static AmzCD()
|
||||
{
|
||||
m_waitUntilLock = new object();
|
||||
m_waitUntilAuthId = new Dictionary<string, DateTime>();
|
||||
m_waitUntilRemotename = new Dictionary<string, DateTime>();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
// This constructor is needed by the BackendLoader.
|
||||
public AmzCD()
|
||||
{
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
// This constructor is needed by the BackendLoader.
|
||||
public AmzCD(string url, Dictionary<string, string> options)
|
||||
{
|
||||
var uri = new Utility.Uri(url);
|
||||
m_path = Util.AppendDirSeparator(uri.HostAndPath, "/");
|
||||
|
||||
if (options.ContainsKey(AUTHID_OPTION))
|
||||
m_authid = options[AUTHID_OPTION];
|
||||
|
||||
string labels = DEFAULT_LABELS;
|
||||
if (options.ContainsKey(LABELS_OPTION))
|
||||
labels = options[LABELS_OPTION];
|
||||
|
||||
string delay = DEFAULT_DELAY;
|
||||
if (options.ContainsKey(DELAY_OPTION))
|
||||
delay = options[DELAY_OPTION];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(labels))
|
||||
m_labels = labels.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(delay))
|
||||
m_delayTimeSpan = new TimeSpan(0);
|
||||
else
|
||||
m_delayTimeSpan = Library.Utility.Timeparser.ParseTimeSpan(delay);
|
||||
|
||||
m_oauth = new OAuthHelper(m_authid, this.ProtocolKey) { AutoAuthHeader = true };
|
||||
m_userid = m_authid.Split(new [] {":"}, StringSplitOptions.RemoveEmptyEntries).First();
|
||||
}
|
||||
|
||||
private static void CleanWaitUntil()
|
||||
{
|
||||
lock (m_waitUntilLock)
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
m_waitUntilRemotename = m_waitUntilRemotename.Where(pair => pair.Value > now)
|
||||
.ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime GetWaitUntil(string remotename)
|
||||
{
|
||||
lock (m_waitUntilLock)
|
||||
{
|
||||
CleanWaitUntil();
|
||||
|
||||
DateTime result;
|
||||
if (string.IsNullOrEmpty(remotename))
|
||||
{
|
||||
if (m_waitUntilAuthId.TryGetValue(m_authid, out result))
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_waitUntilRemotename.TryGetValue(remotename, out result))
|
||||
return result;
|
||||
}
|
||||
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetWaitUntil(string remotename, DateTime value)
|
||||
{
|
||||
lock (m_waitUntilLock)
|
||||
{
|
||||
DateTime oldValue;
|
||||
|
||||
if (!string.IsNullOrEmpty(remotename))
|
||||
{
|
||||
if (!m_waitUntilRemotename.TryGetValue(remotename, out oldValue) || value > oldValue)
|
||||
m_waitUntilRemotename[remotename] = value;
|
||||
}
|
||||
|
||||
if (!m_waitUntilAuthId.TryGetValue(m_authid, out oldValue) || value > oldValue)
|
||||
m_waitUntilAuthId[m_authid] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnforceConsistencyDelay(string remotename)
|
||||
{
|
||||
var wait = GetWaitUntil(remotename) - DateTime.Now;
|
||||
|
||||
if (wait.Ticks > 0)
|
||||
Thread.Sleep(wait);
|
||||
}
|
||||
|
||||
private string CacheFilePath { get { return SystemIO.IO_OS.PathCombine(Utility.TempFolder.SystemTempPath, string.Format(CACHE_FILE_NAME_TEMPLATE, m_userid)); } }
|
||||
|
||||
private void RefreshMetadataAndContentUrl()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(CacheFilePath) && (DateTime.Now - File.GetLastWriteTime(CacheFilePath)) < KEEP_CACHE_FILE_TIME)
|
||||
{
|
||||
m_endPointInfo = JsonConvert.DeserializeObject<EndpointInfo>(File.ReadAllText(CacheFilePath));
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
m_endPointInfo = m_oauth.GetJSONData<EndpointInfo>(CLOUDRIVE_MASTER_URL);
|
||||
|
||||
try
|
||||
{
|
||||
if (m_endPointInfo.CustomerExists && m_endPointInfo.ContentUrl != null && m_endPointInfo.MetadataUrl != null)
|
||||
File.WriteAllText(CacheFilePath, JsonConvert.SerializeObject(m_endPointInfo));
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public string ContentUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_endPointInfo == null)
|
||||
RefreshMetadataAndContentUrl();
|
||||
while (m_endPointInfo.ContentUrl.EndsWith("/", StringComparison.Ordinal))
|
||||
m_endPointInfo.ContentUrl = m_endPointInfo.ContentUrl.Substring(0, m_endPointInfo.ContentUrl.Length - 1);
|
||||
return m_endPointInfo.ContentUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public string MetadataUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_endPointInfo == null)
|
||||
RefreshMetadataAndContentUrl();
|
||||
while (m_endPointInfo.MetadataUrl.EndsWith("/", StringComparison.Ordinal))
|
||||
m_endPointInfo.MetadataUrl = m_endPointInfo.MetadataUrl.Substring(0, m_endPointInfo.MetadataUrl.Length - 1);
|
||||
return m_endPointInfo.MetadataUrl;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, string> FileCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_filecache == null)
|
||||
List();
|
||||
|
||||
return m_filecache;
|
||||
}
|
||||
}
|
||||
|
||||
private ResourceModel GetCurrentDirectory(bool createMissing, string altpath = null)
|
||||
{
|
||||
var rootResponse = m_oauth.GetJSONData<ListResponse>(string.Format("{0}/nodes?filters=isRoot:true", MetadataUrl));
|
||||
var parent = rootResponse.Data.First();
|
||||
var curpath = new List<string>();
|
||||
foreach(var p in (altpath ?? m_path).Split(new string[] {"/"}, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var requestUrl = string.Format("{0}/nodes?filters=kind:{1}%20and%20parents:{2}%20and%20name:{3}", MetadataUrl, CONTENT_KIND_FOLDER, Utility.Uri.UrlEncode(parent.ID), Utility.Uri.UrlPathEncode(EscapeFiltersValue(p)));
|
||||
var self = m_oauth.GetJSONData<ListResponse>(requestUrl);
|
||||
if (self == null || self.Count == 0 || self.Data == null || self.Data.Length == 0)
|
||||
{
|
||||
if (!createMissing)
|
||||
throw new FolderMissingException(string.Format("Unable to find folder {0} in {1}", p, "/" + string.Join("/", curpath)));
|
||||
|
||||
// Create the folder
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new CreateItemRequest() {
|
||||
Name = p,
|
||||
Parents = new string[] { parent.ID },
|
||||
Kind = CONTENT_KIND_FOLDER,
|
||||
Labels = m_labels
|
||||
}));
|
||||
|
||||
parent = m_oauth.GetJSONData<ResourceModel>(
|
||||
string.Format("{0}/nodes", MetadataUrl),
|
||||
|
||||
// Setup
|
||||
req =>
|
||||
{
|
||||
req.Method = "POST";
|
||||
req.ContentLength = data.Length;
|
||||
req.ContentType = "application/json";
|
||||
},
|
||||
|
||||
// Post the folder entry
|
||||
req =>
|
||||
{
|
||||
using(var rs = req.GetRequestStream())
|
||||
rs.Write(data, 0, data.Length);
|
||||
}
|
||||
);
|
||||
SetWaitUntil(null, DateTime.Now + m_delayTimeSpan);
|
||||
}
|
||||
else if (self.Count > 1)
|
||||
throw new UserInformationException(Strings.AmzCD.MultipleEntries(p, "/" + string.Join("/", curpath)), "AmzCDMultipleEntries");
|
||||
else
|
||||
parent = self.Data.First();
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
private ResourceModel CurrentDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_curdir == null)
|
||||
m_curdir = GetCurrentDirectory(false);
|
||||
|
||||
return m_curdir;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetFileID(string name)
|
||||
{
|
||||
var recent = m_filecache == null;
|
||||
|
||||
string id;
|
||||
FileCache.TryGetValue(name, out id);
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
return id;
|
||||
|
||||
// Reset to make sure it is actually missing
|
||||
if (!recent)
|
||||
{
|
||||
List();
|
||||
|
||||
FileCache.TryGetValue(name, out id);
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
return id;
|
||||
}
|
||||
|
||||
throw new FileMissingException();
|
||||
}
|
||||
|
||||
private static readonly System.Text.RegularExpressions.Regex FILTERS_VALUE_ESCAPECHAR = new System.Text.RegularExpressions.Regex(@"[+\-&|!(){}\[\]^'""~*?:\\ ]", System.Text.RegularExpressions.RegexOptions.Compiled);
|
||||
|
||||
public static string EscapeFiltersValue(string value)
|
||||
{
|
||||
return FILTERS_VALUE_ESCAPECHAR.Replace(value, (m) => {
|
||||
return @"\" + m.Value;
|
||||
});
|
||||
}
|
||||
|
||||
#region IStreamingBackend implementation
|
||||
|
||||
public async Task PutAsync(string remotename, Stream stream, CancellationToken cancelToken)
|
||||
{
|
||||
EnforceConsistencyDelay(remotename);
|
||||
|
||||
var overwrite = FileCache.ContainsKey(remotename);
|
||||
var fileid = overwrite ? m_filecache[remotename] : null;
|
||||
|
||||
var url = string.Format(overwrite ? "{0}/nodes/{1}/content?suppress=deduplication" : "{0}/nodes?suppress=deduplication", ContentUrl, fileid);
|
||||
|
||||
var createreq = new CreateItemRequest() {
|
||||
Name = remotename,
|
||||
Kind = CONTENT_KIND_FILE,
|
||||
Labels = m_labels,
|
||||
Parents = new string[] { CurrentDirectory.ID }
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var item = await m_oauth.PostMultipartAndGetJSONDataAsync<ResourceModel>(
|
||||
url,
|
||||
req =>
|
||||
{
|
||||
req.Method = overwrite ? "PUT" : "POST";
|
||||
},
|
||||
cancelToken,
|
||||
new MultipartItem(createreq, "metadata"),
|
||||
new MultipartItem(stream, "content", remotename)
|
||||
).ConfigureAwait(false);
|
||||
|
||||
if (m_filecache != null)
|
||||
m_filecache[item.Name] = item.ID;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
if (ex is WebException exception)
|
||||
using(var sr = new StreamReader(exception.Response.GetResponseStream()))
|
||||
Console.WriteLine(sr.ReadToEnd());
|
||||
#endif
|
||||
|
||||
m_filecache = null;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetWaitUntil(remotename, DateTime.Now + m_delayTimeSpan);
|
||||
}
|
||||
}
|
||||
|
||||
public void Get(string remotename, Stream stream)
|
||||
{
|
||||
EnforceConsistencyDelay(remotename);
|
||||
|
||||
using (var resp = m_oauth.GetResponse(string.Format("{0}/nodes/{1}/content", ContentUrl, GetFileID(remotename))))
|
||||
using(var rs = Library.Utility.AsyncHttpRequest.TrySetTimeout(resp.GetResponseStream()))
|
||||
Utility.Utility.CopyStream(rs, stream);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBackend implementation
|
||||
|
||||
public IEnumerable<IFileEntry> List()
|
||||
{
|
||||
EnforceConsistencyDelay(null);
|
||||
|
||||
var query = string.Format("{0}/nodes?filters=parents:{1}&limit={2}", MetadataUrl, Utility.Uri.UrlEncode(CurrentDirectory.ID), PAGE_SIZE);
|
||||
var res = new List<IFileEntry>();
|
||||
string nextToken = null;
|
||||
m_filecache = null;
|
||||
var cache = new Dictionary<string, string>();
|
||||
|
||||
do
|
||||
{
|
||||
var lst = m_oauth.GetJSONData<ListResponse>(query + (string.IsNullOrWhiteSpace(nextToken) ? "" : ("&startToken=" + nextToken)));
|
||||
if (lst.Data != null)
|
||||
{
|
||||
foreach(var n in lst.Data)
|
||||
{
|
||||
|
||||
if (string.Equals(CONTENT_KIND_FOLDER, n.Kind, StringComparison.OrdinalIgnoreCase))
|
||||
res.Add(new FileEntry(n.Name) { IsFolder = true });
|
||||
else if (string.Equals(CONTENT_KIND_FILE, n.Kind, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
cache[n.Name] = n.ID;
|
||||
|
||||
if (n.ContentProperties == null)
|
||||
res.Add(new FileEntry(n.Name) {
|
||||
LastAccess = n.LastModified,
|
||||
LastModification = n.LastModified
|
||||
});
|
||||
else
|
||||
res.Add(new FileEntry(n.Name, n.ContentProperties.Size, n.LastModified, n.LastModified));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextToken = lst.NextToken;
|
||||
|
||||
// Contrary to the documentation, nextToken is null when the set is done
|
||||
if (lst.Count == 0)
|
||||
break;
|
||||
|
||||
// Docs say to check for empty response ...
|
||||
//if (lst.Count < PAGE_SIZE)
|
||||
// break;
|
||||
} while(nextToken != null);
|
||||
|
||||
m_filecache = cache;
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
public Task PutAsync(string remotename, string filename, CancellationToken cancelToken)
|
||||
{
|
||||
using (FileStream fs = File.OpenRead(filename))
|
||||
return PutAsync(remotename, fs, cancelToken);
|
||||
}
|
||||
|
||||
public void Get(string remotename, string filename)
|
||||
{
|
||||
using (FileStream fs = File.Create(filename))
|
||||
Get(remotename, fs);
|
||||
}
|
||||
|
||||
public void Delete(string remotename)
|
||||
{
|
||||
EnforceConsistencyDelay(remotename);
|
||||
|
||||
try
|
||||
{
|
||||
using (m_oauth.GetResponse(string.Format("{0}/trash/{1}", MetadataUrl, GetFileID(remotename)), null, "PUT"))
|
||||
{
|
||||
}
|
||||
|
||||
m_filecache.Remove(remotename);
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_filecache = null;
|
||||
}
|
||||
SetWaitUntil(remotename, DateTime.Now + m_delayTimeSpan);
|
||||
}
|
||||
|
||||
public void Test()
|
||||
{
|
||||
this.TestList();
|
||||
}
|
||||
|
||||
public void CreateFolder()
|
||||
{
|
||||
EnforceConsistencyDelay(null);
|
||||
GetCurrentDirectory(true);
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
return Strings.AmzCD.DisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
public string ProtocolKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return "amzcd";
|
||||
}
|
||||
}
|
||||
|
||||
public IList<ICommandLineArgument> SupportedCommands
|
||||
{
|
||||
get {
|
||||
return new List<ICommandLineArgument>(new ICommandLineArgument[] {
|
||||
new CommandLineArgument(AUTHID_OPTION, CommandLineArgument.ArgumentType.Password, Strings.AmzCD.AuthidShort, Strings.AmzCD.AuthidLong(OAuthHelper.OAUTH_LOGIN_URL("amzcd"))),
|
||||
new CommandLineArgument(LABELS_OPTION, CommandLineArgument.ArgumentType.String, Strings.AmzCD.LabelsShort, Strings.AmzCD.LabelsLong, DEFAULT_LABELS),
|
||||
new CommandLineArgument(DELAY_OPTION, CommandLineArgument.ArgumentType.Timespan, Strings.AmzCD.DelayShort, Strings.AmzCD.DelayLong, DEFAULT_DELAY),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return Strings.AmzCD.Description;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] DNSName
|
||||
{
|
||||
get
|
||||
{
|
||||
var contentUrl = string.Empty;
|
||||
var metdataUrl = string.Empty;
|
||||
|
||||
if (m_endPointInfo != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(m_endPointInfo.ContentUrl))
|
||||
contentUrl = new Uri(m_endPointInfo.ContentUrl).Host;
|
||||
if (!string.IsNullOrWhiteSpace(m_endPointInfo.MetadataUrl))
|
||||
metdataUrl = new Uri(m_endPointInfo.MetadataUrl).Host;
|
||||
}
|
||||
|
||||
return new string[] {
|
||||
new Uri(CLOUDRIVE_MASTER_URL).Host,
|
||||
contentUrl,
|
||||
metdataUrl
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IRenameEnabledBackend
|
||||
|
||||
public void Rename(string oldname, string newname)
|
||||
{
|
||||
EnforceConsistencyDelay(oldname);
|
||||
|
||||
var id = GetFileID(oldname);
|
||||
|
||||
var data = System.Text.Encoding.UTF8.GetBytes(
|
||||
JsonConvert.SerializeObject(new CreateItemRequest() { Name = newname })
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
var resp = m_oauth.GetJSONData<ResourceModel>(
|
||||
string.Format("{0}/nodes/{1}", MetadataUrl, id),
|
||||
req =>
|
||||
{
|
||||
req.Method = "PATCH";
|
||||
req.ContentType = "application/json";
|
||||
req.ContentLength = data.Length;
|
||||
},
|
||||
|
||||
req =>
|
||||
{
|
||||
using (var rs = req.GetRequestStream())
|
||||
rs.Write(data, 0, data.Length);
|
||||
}
|
||||
);
|
||||
|
||||
m_filecache.Remove(oldname);
|
||||
m_filecache[newname] = resp.ID;
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_filecache = null;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetWaitUntil(oldname, DateTime.Now + m_delayTimeSpan);
|
||||
SetWaitUntil(newname, DateTime.Now + m_delayTimeSpan);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region JSON Classes
|
||||
|
||||
private class ListResponse
|
||||
{
|
||||
[JsonProperty("count")]
|
||||
public long Count { get; set; }
|
||||
[JsonProperty("nextToken")]
|
||||
public string NextToken { get; set; }
|
||||
[JsonProperty("data")]
|
||||
public ResourceModel[] Data { get; set; }
|
||||
}
|
||||
|
||||
private class ResourceModel
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string ID { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonProperty("kind")]
|
||||
public string Kind { get; set; }
|
||||
[JsonProperty("version")]
|
||||
public long Version { get; set; }
|
||||
[JsonProperty("modifiedDate")]
|
||||
public DateTime LastModified { get; set; }
|
||||
[JsonProperty("createdDate")]
|
||||
public DateTime CreatedDate { get; set; }
|
||||
[JsonProperty("labels")]
|
||||
public string[] Labels { get; set; }
|
||||
[JsonProperty("description")]
|
||||
public string Description { get; set; }
|
||||
[JsonProperty("createdBy")]
|
||||
public string CreatedBy { get; set; }
|
||||
[JsonProperty("parents")]
|
||||
public string[] Parents { get; set; }
|
||||
[JsonProperty("status")]
|
||||
public string Status { get; set; }
|
||||
[JsonProperty("contentProperties")]
|
||||
public ContentProperties ContentProperties { get; set; }
|
||||
}
|
||||
|
||||
private class ContentProperties
|
||||
{
|
||||
[JsonProperty("version")]
|
||||
public long Version { get; set; }
|
||||
[JsonProperty("md5")]
|
||||
public string MD5 { get; set; }
|
||||
[JsonProperty("size")]
|
||||
public long Size { get; set; }
|
||||
|
||||
[JsonProperty("contentType")]
|
||||
public string ContentType { get; set; }
|
||||
[JsonProperty("extension")]
|
||||
public string Extension { get; set; }
|
||||
[JsonProperty("contentDate")]
|
||||
public DateTime ContentDate { get; set; }
|
||||
}
|
||||
|
||||
private class EndpointInfo
|
||||
{
|
||||
[JsonProperty("customerExists")]
|
||||
public bool CustomerExists { get; set; }
|
||||
[JsonProperty("contentUrl")]
|
||||
public string ContentUrl { get; set; }
|
||||
[JsonProperty("metadataUrl")]
|
||||
public string MetadataUrl { get; set; }
|
||||
}
|
||||
|
||||
private class CreateItemRequest
|
||||
{
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
[JsonProperty("kind")]
|
||||
public string Kind { get; set; }
|
||||
[JsonProperty("labels", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string[] Labels { get; set; }
|
||||
[JsonProperty("properties", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public Dictionary<string, string> Properties { get; set; }
|
||||
[JsonProperty("parents")]
|
||||
public string[] Parents { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{08D7E42D-285C-4010-9881-986125FE2F3E}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Duplicati.Library.Backend.AmazonCloudDrive</RootNamespace>
|
||||
<AssemblyName>Duplicati.Library.Backend.AmazonCloudDrive</AssemblyName>
|
||||
<AssemblyOriginatorKeyFile>Duplicati.snk</AssemblyOriginatorKeyFile>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<UseMSBuildEngine>false</UseMSBuildEngine>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="AmzCD.cs" />
|
||||
<Compile Include="Strings.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Localization\Duplicati.Library.Localization.csproj">
|
||||
<Project>{B68F2214-951F-4F78-8488-66E1ED3F50BF}</Project>
|
||||
<Name>Duplicati.Library.Localization</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\OAuthHelper\Duplicati.Library.OAuthHelper.csproj">
|
||||
<Project>{D4C37C33-5E73-4B56-B2C3-DC4A6BAA36BB}</Project>
|
||||
<Name>Duplicati.Library.OAuthHelper</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Utility\Duplicati.Library.Utility.csproj">
|
||||
<Project>{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}</Project>
|
||||
<Name>Duplicati.Library.Utility</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Interface\Duplicati.Library.Interface.csproj">
|
||||
<Project>{C5899F45-B0FF-483C-9D38-24A9FCAAB237}</Project>
|
||||
<Name>Duplicati.Library.Interface</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Common\Duplicati.Library.Common.csproj">
|
||||
<Project>{D63E53E4-A458-4C2F-914D-92F715F58ACF}</Project>
|
||||
<Name>Duplicati.Library.Common</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
@@ -1,43 +0,0 @@
|
||||
// Copyright (C) 2015, The Duplicati Team
|
||||
// http://www.duplicati.com, info@duplicati.com
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("Duplicati.Library.Backend.AmazonCloudDrive")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("kenneth")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("2.0.0.7")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright (C) 2015, The Duplicati Team
|
||||
// http://www.duplicati.com, info@duplicati.com
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
using Duplicati.Library.Localization.Short;
|
||||
|
||||
namespace Duplicati.Library.Backend.Strings
|
||||
{
|
||||
internal static class AmzCD
|
||||
{
|
||||
public static string Description { get { return LC.L(@"This backend can read and write data to Amazon Cloud Drive. Supported format is ""amzcd://folder/subfolder""."); } }
|
||||
public static string AuthidShort { get { return LC.L(@"The authorization code"); } }
|
||||
public static string AuthidLong(string url) { return LC.L(@"The authorization token retrieved from {0}", url); }
|
||||
public static string DisplayName { get { return LC.L(@"Amazon Cloud Drive"); } }
|
||||
public static string LabelsShort { get { return LC.L(@"The labels to set"); } }
|
||||
public static string LabelsLong { get { return LC.L(@"Use this option to set labels on the files and folders created"); } }
|
||||
public static string MultipleEntries(string folder, string parent) { return LC.L(@"There is more than one item named ""{0}"" in the folder ""{1}""", folder, parent); }
|
||||
public static string DelayShort { get { return LC.L(@"The consistency delay"); } }
|
||||
public static string DelayLong { get { return LC.L(@"Amazon Cloud drive needs a small delay for results to stay consistent."); } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net462" />
|
||||
</packages>
|
||||
@@ -803,10 +803,6 @@ namespace Duplicati.Library.Main
|
||||
if (string.Equals(m_options.CompressionModule, "7z", StringComparison.OrdinalIgnoreCase))
|
||||
Logging.Log.WriteWarningMessage(LOGTAG, "7zModuleHasIssues", null, "The 7z compression module has known issues and should only be used for experimental purposes");
|
||||
|
||||
// Amazon CD is closing August 16th 2019
|
||||
if (string.Equals(new Library.Utility.Uri(m_backend).Scheme, "amzcd", StringComparison.OrdinalIgnoreCase))
|
||||
Logging.Log.WriteWarningMessage(LOGTAG, "AmzCDClosingApi", null, "The Amazon Cloud Drive API is closing down on August 16th 2019, please migrate your backups before this date");
|
||||
|
||||
//TODO: Based on the action, see if all options are relevant
|
||||
}
|
||||
|
||||
|
||||
@@ -291,10 +291,6 @@
|
||||
<Project>{4A010589-76E6-4F05-A5C4-4598D5DF11F8}</Project>
|
||||
<Name>Duplicati.CommandLine.RecoveryTool</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\AmazonCloudDrive\Duplicati.Library.Backend.AmazonCloudDrive.csproj">
|
||||
<Project>{08D7E42D-285C-4010-9881-986125FE2F3E}</Project>
|
||||
<Name>Duplicati.Library.Backend.AmazonCloudDrive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Library\Backend\Backblaze\Duplicati.Library.Backend.Backblaze.csproj">
|
||||
<Project>{61C43D61-4368-4942-84A3-1EB623F4EF2A}</Project>
|
||||
<Name>Duplicati.Library.Backend.Backblaze</Name>
|
||||
@@ -338,4 +334,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -26,7 +26,6 @@ backupApp.directive('advancedOptionsEditor', function() {
|
||||
'throttle-download': 'speed',
|
||||
|
||||
'retry-delay': 'shorttimespan',
|
||||
'amzcd-consistency-delay': 'shorttimespan',
|
||||
'web-timeout': 'shorttimespan',
|
||||
'run-script-timeout': 'shorttimespan'
|
||||
};
|
||||
|
||||
@@ -20,7 +20,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo,
|
||||
EditUriBackendConfig.templates['onedrivev2'] = 'templates/backends/oauth.html';
|
||||
EditUriBackendConfig.templates['sharepoint'] = 'templates/backends/sharepoint.html';
|
||||
EditUriBackendConfig.templates['msgroup'] = 'templates/backends/msgroup.html';
|
||||
EditUriBackendConfig.templates['amzcd'] = 'templates/backends/amzcd.html';
|
||||
EditUriBackendConfig.templates['openstack'] = 'templates/backends/openstack.html';
|
||||
EditUriBackendConfig.templates['azure'] = 'templates/backends/azure.html';
|
||||
EditUriBackendConfig.templates['gcs'] = 'templates/backends/gcs.html';
|
||||
@@ -199,7 +198,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo,
|
||||
EditUriBackendConfig.loaders['onedrivev2'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.loaders['sharepoint'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.loaders['msgroup'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.loaders['amzcd'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.loaders['box'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.loaders['dropbox'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
|
||||
@@ -322,7 +320,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo,
|
||||
EditUriBackendConfig.parsers['onedrive'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.parsers['onedrivev2'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.parsers['sharepoint'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.parsers['amzcd'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.parsers['box'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.parsers['dropbox'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
|
||||
@@ -474,7 +471,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo,
|
||||
EditUriBackendConfig.builders['onedrivev2'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.builders['sharepoint'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.builders['msgroup'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.builders['amzcd'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.builders['box'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
EditUriBackendConfig.builders['dropbox'] = function() { return this['oauth-base'].apply(this, arguments); };
|
||||
|
||||
@@ -718,7 +714,6 @@ backupApp.service('EditUriBuiltins', function(AppService, AppUtils, SystemInfo,
|
||||
|
||||
EditUriBackendConfig.validaters['googledrive'] = EditUriBackendConfig.validaters['authid-base'];
|
||||
EditUriBackendConfig.validaters['gcs'] = EditUriBackendConfig.validaters['authid-base'];
|
||||
EditUriBackendConfig.validaters['amzcd'] = EditUriBackendConfig.validaters['authid-base'];
|
||||
EditUriBackendConfig.validaters['box'] = EditUriBackendConfig.validaters['authid-base'];
|
||||
EditUriBackendConfig.validaters['dropbox'] = EditUriBackendConfig.validaters['authid-base'];
|
||||
EditUriBackendConfig.validaters['onedrive'] = EditUriBackendConfig.validaters['authid-base'];
|
||||
|
||||
@@ -64,7 +64,6 @@ backupApp.service('SystemInfo', function($rootScope, $timeout, $cookies, AppServ
|
||||
'gcs': null,
|
||||
'openstack': null,
|
||||
'hubic': null,
|
||||
'amzcd': null,
|
||||
'b2': null,
|
||||
'mega': null,
|
||||
'box': null,
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<h2 style="color: darkred">WARNING: Amazon Cloud Drive API is closing August 16th 2019</h2>
|
||||
<p>Do not use this destination for new backups, and migrate any existing backups away before this date</p>
|
||||
|
||||
<div class="input text">
|
||||
<label for="oauth_path" translate>Path on server</label>
|
||||
<input type="text" name="oauth_path" id="oauth_path" ng-model="$parent.Path" placeholder="{{'Enter the destination path' | translate}}" />
|
||||
</div>
|
||||
|
||||
<div class="input text">
|
||||
<label for="oauth_authid">
|
||||
<a ng-show="oauth_in_progress" href="{{oauth_start_link}}" target="_blank" translate>AuthID</a>
|
||||
<a ng-hide="oauth_in_progress" href ng-click="oauth_start_token_creation()" translate>AuthID</a>
|
||||
</label>
|
||||
<input type="text" name="oauth_authid" id="oauth_authid" ng-model="$parent.AuthID" placeholder="{{'Click the AuthID link to create an AuthID' | translate}}" />
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
# [Duplicati](https://www.duplicati.com)
|
||||
Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with:
|
||||
|
||||
*Amazon S3, OneDrive, Google Drive, Rackspace Cloud Files, HubiC, Backblaze (B2), Amazon Cloud Drive (AmzCD), Swift / OpenStack, WebDAV, SSH (SFTP), FTP, and more!*
|
||||
*Amazon S3, OneDrive, Google Drive, Rackspace Cloud Files, HubiC, Backblaze (B2), Swift / OpenStack, WebDAV, SSH (SFTP), FTP, and more!*
|
||||
|
||||
Duplicati is licensed under LGPL and available for Windows, OSX and Linux (.NET 4.6.2+ or Mono 4.8.0+ required).
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Removed Gitter
|
||||
|
||||
Duplicati is a free, open source, backup client that securely stores encrypted, incremental, compressed backups on cloud storage services and remote file servers. It works with:
|
||||
|
||||
*Amazon Cloud Drive and S3, [Backblaze (B2)](https://www.backblaze.com/blog/duplicati-backups-cloud-storage/ "Duplicati with Backblaze B2 Cloud Storage"), Box, Dropbox, FTP, Google Cloud and Drive, HubiC, MEGA, Microsoft Azure and OneDrive, Rackspace Cloud Files, OpenStack Storage (Swift), Sia, SSH (SFTP), WebDAV, [and more!](https://duplicati.readthedocs.io/en/latest/01-introduction/#supported-backends)*
|
||||
*Amazon S3, [Backblaze (B2)](https://www.backblaze.com/blog/duplicati-backups-cloud-storage/ "Duplicati with Backblaze B2 Cloud Storage"), Box, Dropbox, FTP, Google Cloud and Drive, HubiC, MEGA, Microsoft Azure and OneDrive, Rackspace Cloud Files, OpenStack Storage (Swift), Sia, SSH (SFTP), WebDAV, [and more!](https://duplicati.readthedocs.io/en/latest/01-introduction/#supported-backends)*
|
||||
|
||||
Duplicati is licensed under LGPL and available for Windows, OSX and Linux (.NET 4.6.2+ or Mono 4.8.0+ required).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user