diff --git a/Duplicati/Library/Backend/Duplicati/ListBackupsModule.cs b/Duplicati/Library/Backend/Duplicati/ListBackupsModule.cs
index 179096b14..0b9e01dcf 100644
--- a/Duplicati/Library/Backend/Duplicati/ListBackupsModule.cs
+++ b/Duplicati/Library/Backend/Duplicati/ListBackupsModule.cs
@@ -43,7 +43,7 @@ public class ListBackupsModule : IWebModule
}
///
- public IDictionary Execute(IDictionary options)
+ public async Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
var opts = new Dictionary(options);
@@ -71,7 +71,7 @@ public class ListBackupsModule : IWebModule
using var backend = new DuplicatiBackend(url, opts);
return new Dictionary()
{
- { "folders", JsonSerializer.Serialize( backend.ListBackupFolders(CancellationToken.None).ToArrayAsync().Await()) }
+ { "folders", JsonSerializer.Serialize( await backend.ListBackupFolders(cancellationToken).ToArrayAsync(cancellationToken) ) }
};
}
diff --git a/Duplicati/Library/Backend/Filen/GetApiKeyModule.cs b/Duplicati/Library/Backend/Filen/GetApiKeyModule.cs
index ac0cf6325..329bd13d5 100644
--- a/Duplicati/Library/Backend/Filen/GetApiKeyModule.cs
+++ b/Duplicati/Library/Backend/Filen/GetApiKeyModule.cs
@@ -53,7 +53,7 @@ public class GetApiKeyModule : IWebModule
];
///
- public IDictionary Execute(IDictionary options)
+ public async Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
options.TryGetValue("filen-operation", out var operation);
if (operation != "GetApiKey")
@@ -71,7 +71,7 @@ public class GetApiKeyModule : IWebModule
newOpts[key] = uri.QueryParameters[key];
var backend = new FilenBackend(url, newOpts);
- var apiKey = backend.GetApiKey(CancellationToken.None).Await();
+ var apiKey = await backend.GetApiKey(cancellationToken).ConfigureAwait(false);
return new Dictionary { { "api-key", apiKey ?? string.Empty } };
}
diff --git a/Duplicati/Library/Backend/GoogleServices/GCSConfig.cs b/Duplicati/Library/Backend/GoogleServices/GCSConfig.cs
index a1cc64f6d..ba9156b82 100644
--- a/Duplicati/Library/Backend/GoogleServices/GCSConfig.cs
+++ b/Duplicati/Library/Backend/GoogleServices/GCSConfig.cs
@@ -42,11 +42,11 @@ namespace Duplicati.Library.Backend.GoogleServices
#region IWebModule implementation
- public IDictionary Execute(IDictionary options)
+ public Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
var ct = Utility.Utility.ParseEnumOption(options.AsReadOnly(), KEY_CONFIGTYPE, DEFAULT_CONFIG_TYPE);
GetLookups().TryGetValue(ct.ToString(), out var dict);
- return dict ?? new Dictionary();
+ return Task.FromResult(dict ?? new Dictionary());
}
public string Key => "gcs-getconfig";
diff --git a/Duplicati/Library/Backend/OpenStack/SwiftConfig.cs b/Duplicati/Library/Backend/OpenStack/SwiftConfig.cs
index 25dbd36da..9fa5a1135 100644
--- a/Duplicati/Library/Backend/OpenStack/SwiftConfig.cs
+++ b/Duplicati/Library/Backend/OpenStack/SwiftConfig.cs
@@ -38,11 +38,11 @@ namespace Duplicati.Library.Backend.OpenStack
{
}
- public IDictionary Execute(IDictionary options)
+ public Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
var ct = Utility.Utility.ParseEnumOption(options.AsReadOnly(), KEY_CONFIGTYPE, DEFAULT_CONFIG_TYPE);
GetLookups().TryGetValue(ct.ToString(), out var dict);
- return dict ?? new Dictionary();
+ return Task.FromResult(dict ?? new Dictionary());
}
public string Key => "openstack-getconfig";
diff --git a/Duplicati/Library/Backend/S3/S3Config.cs b/Duplicati/Library/Backend/S3/S3Config.cs
index 1af03f4a8..8c709619d 100644
--- a/Duplicati/Library/Backend/S3/S3Config.cs
+++ b/Duplicati/Library/Backend/S3/S3Config.cs
@@ -43,11 +43,11 @@ namespace Duplicati.Library.Backend
#region IWebModule implementation
- public IDictionary Execute(IDictionary options)
+ public Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
var ct = Utility.Utility.ParseEnumOption(options.AsReadOnly(), KEY_CONFIGTYPE, DEFAULT_CONFIG_TYPE);
GetLookups().TryGetValue(ct.ToString(), out var dict);
- return dict ?? new Dictionary();
+ return Task.FromResult(dict ?? new Dictionary());
}
public string Key => "s3-getconfig";
diff --git a/Duplicati/Library/Backend/S3/S3IAM.cs b/Duplicati/Library/Backend/S3/S3IAM.cs
index ba3b7f472..f9c0f628b 100644
--- a/Duplicati/Library/Backend/S3/S3IAM.cs
+++ b/Duplicati/Library/Backend/S3/S3IAM.cs
@@ -76,7 +76,7 @@ namespace Duplicati.Library.Backend
new CommandLineArgument(KEY_PASSWORD, CommandLineArgument.ArgumentType.String, Strings.S3IAM.PasswordShort, Strings.S3IAM.PasswordLong)
]);
- public IDictionary Execute(IDictionary options)
+ public async Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
options.TryGetValue(KEY_OPERATION, out var operationstring);
options.TryGetValue(KEY_USERNAME, out var username);
@@ -98,12 +98,12 @@ namespace Duplicati.Library.Backend
ValidateArgument(username, KEY_USERNAME);
ValidateArgument(password, KEY_PASSWORD);
ValidateArgument(path, KEY_PATH);
- return CreateUnprivilegedUser(username!, password!, path!);
+ return await CreateUnprivilegedUser(username!, password!, path!, cancellationToken).ConfigureAwait(false);
default:
ValidateArgument(username, KEY_USERNAME);
ValidateArgument(password, KEY_PASSWORD);
- return CanCreateUser(username!, password!);
+ return await CanCreateUser(username!, password!, cancellationToken).ConfigureAwait(false);
}
}
@@ -138,7 +138,7 @@ namespace Duplicati.Library.Backend
}
- private static bool DetermineIfCreateUserIsAllowed(User user, AmazonIdentityManagementServiceClient cl)
+ private static async Task DetermineIfCreateUserIsAllowed(User user, AmazonIdentityManagementServiceClient cl, CancellationToken cancellationToken)
{
var simulatePrincipalPolicy = new SimulatePrincipalPolicyRequest
{
@@ -146,13 +146,12 @@ namespace Duplicati.Library.Backend
ActionNames = new[] { "iam:CreateUser" }.ToList()
};
- return cl.SimulatePrincipalPolicyAsync(simulatePrincipalPolicy)
- .GetAwaiter().GetResult()
- .EvaluationResults.First()
- .EvalDecision == PolicyEvaluationDecisionType.Allowed;
+ return (await cl.SimulatePrincipalPolicyAsync(simulatePrincipalPolicy, cancellationToken).ConfigureAwait(false))
+ .EvaluationResults.First()
+ .EvalDecision == PolicyEvaluationDecisionType.Allowed;
}
- private static IDictionary GetCreateUserDict(User user, AmazonIdentityManagementServiceClient cl)
+ private static async Task> GetCreateUserDict(User user, AmazonIdentityManagementServiceClient cl, CancellationToken cancellationToken)
{
var resultDict = new Dictionary
{
@@ -164,7 +163,7 @@ namespace Duplicati.Library.Backend
try
{
- resultDict["isroot"] = DetermineIfCreateUserIsAllowed(user, cl).ToString();
+ resultDict["isroot"] = (await DetermineIfCreateUserIsAllowed(user, cl, cancellationToken)).ToString();
}
catch (Exception ex)
{
@@ -180,13 +179,13 @@ namespace Duplicati.Library.Backend
return resultDict;
}
- private static IDictionary CanCreateUser(string awsid, string awskey)
+ private static async Task> CanCreateUser(string awsid, string awskey, CancellationToken cancellationToken)
{
var cl = new AmazonIdentityManagementServiceClient(awsid, awskey);
User user;
try
{
- user = cl.GetUserAsync().Await().User;
+ user = (await cl.GetUserAsync(cancellationToken).ConfigureAwait(false)).User;
}
catch (Exception ex)
{
@@ -198,10 +197,10 @@ namespace Duplicati.Library.Backend
};
}
- return GetCreateUserDict(user, cl);
+ return await GetCreateUserDict(user, cl, cancellationToken);
}
- private static IDictionary CreateUnprivilegedUser(string awsid, string awskey, string path)
+ private static async Task> CreateUnprivilegedUser(string awsid, string awskey, string path, CancellationToken cancellationToken)
{
var now = Utility.Utility.SerializeDateTime(DateTime.Now);
var username = string.Format("duplicati-autocreated-backup-user-{0}", now);
@@ -209,13 +208,13 @@ namespace Duplicati.Library.Backend
var policydoc = GeneratePolicyDoc(path);
var cl = new AmazonIdentityManagementServiceClient(awsid, awskey);
- var user = cl.CreateUserAsync(new CreateUserRequest(username)).GetAwaiter().GetResult().User;
- cl.PutUserPolicyAsync(new PutUserPolicyRequest(
+ var user = (await cl.CreateUserAsync(new CreateUserRequest(username), cancellationToken).ConfigureAwait(false)).User;
+ await cl.PutUserPolicyAsync(new PutUserPolicyRequest(
user.UserName,
policyname,
policydoc
- )).GetAwaiter().GetResult();
- var key = cl.CreateAccessKeyAsync(new CreateAccessKeyRequest { UserName = user.UserName }).GetAwaiter().GetResult().AccessKey;
+ )).ConfigureAwait(false);
+ var key = (await cl.CreateAccessKeyAsync(new CreateAccessKeyRequest { UserName = user.UserName }, cancellationToken).ConfigureAwait(false)).AccessKey;
return new Dictionary
{
diff --git a/Duplicati/Library/Backend/SSHv2/KeyGenerator.cs b/Duplicati/Library/Backend/SSHv2/KeyGenerator.cs
index fab3dec3c..3484b7a6b 100644
--- a/Duplicati/Library/Backend/SSHv2/KeyGenerator.cs
+++ b/Duplicati/Library/Backend/SSHv2/KeyGenerator.cs
@@ -143,7 +143,7 @@ namespace Duplicati.Library.Backend
}
#region IWebModule implementation
- public IDictionary Execute(IDictionary options)
+ public Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
if (!options.TryGetValue(KEY_TYPE_NAME, out var keytype))
keytype = DEFAULT_KEYTYPE;
@@ -174,7 +174,7 @@ namespace Duplicati.Library.Backend
key.Modulus ?? []
};
- return OutputKey(EncodeDER(privateEntries), EncodePEM(publicEntries), KEY_TEMPLATE_RSA, PUB_KEY_FORMAT_RSA, username);
+ return Task.FromResult(OutputKey(EncodeDER(privateEntries), EncodePEM(publicEntries), KEY_TEMPLATE_RSA, PUB_KEY_FORMAT_RSA, username));
}
else if (KEYTYPE_DSA.Equals(keytype, StringComparison.OrdinalIgnoreCase))
{
@@ -195,7 +195,7 @@ namespace Duplicati.Library.Backend
key.Y ?? []
};
- return OutputKey(EncodeDER(privateEntries), EncodePEM(publicEntries), KEY_TEMPLATE_DSA, PUB_KEY_FORMAT_DSA, username);
+ return Task.FromResult(OutputKey(EncodeDER(privateEntries), EncodePEM(publicEntries), KEY_TEMPLATE_DSA, PUB_KEY_FORMAT_DSA, username));
}
else
{
diff --git a/Duplicati/Library/Backend/SSHv2/KeyUploader.cs b/Duplicati/Library/Backend/SSHv2/KeyUploader.cs
index 930a5b4a1..825efd3a4 100644
--- a/Duplicati/Library/Backend/SSHv2/KeyUploader.cs
+++ b/Duplicati/Library/Backend/SSHv2/KeyUploader.cs
@@ -39,7 +39,7 @@ namespace Duplicati.Library.Backend
#region IWebModule implementation
- public IDictionary Execute(IDictionary options)
+ public async Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
var res = new Dictionary();
@@ -65,20 +65,20 @@ namespace Duplicati.Library.Backend
using (var connection = new SSHv2(url, (Dictionary)options))
{
- var client = connection.CreateConnection(CancellationToken.None).Await();
+ var client = await connection.CreateConnection(cancellationToken).ConfigureAwait(false);
try
{
- client.ChangeDirectory(SSH_FOLDER);
+ await client.ChangeDirectoryAsync(SSH_FOLDER, cancellationToken).ConfigureAwait(false);
}
catch
{
- client.CreateDirectory(SSH_FOLDER);
+ await client.CreateDirectoryAsync(SSH_FOLDER, cancellationToken).ConfigureAwait(false);
client.ChangePermissions(SSH_FOLDER, SSH_FOLDER_PERMISSIONS);
- client.ChangeDirectory(SSH_FOLDER);
+ await client.ChangeDirectoryAsync(SSH_FOLDER, cancellationToken).ConfigureAwait(false);
}
- var sshfolder = client.ListDirectory(".").First(x => x.Name == ".");
- client.ChangeDirectory("..");
+ var sshfolder = (await client.ListDirectoryAsync(".", cancellationToken).ToListAsync(cancellationToken)).First(x => x.Name == ".");
+ await client.ChangeDirectoryAsync("..", cancellationToken).ConfigureAwait(false);
if (!sshfolder.OwnerCanRead || !sshfolder.OwnerCanWrite)
client.ChangePermissions(SSH_FOLDER, SSH_FOLDER_PERMISSIONS);
@@ -86,12 +86,12 @@ namespace Duplicati.Library.Backend
var authorized_keys = "";
byte[]? authorized_keys_bytes = null;
- var existing_authorized_keys = client.ListDirectory(SSH_FOLDER).Any(x => x.Name == AUTHORIZED_KEYS_FILE);
+ var existing_authorized_keys = (await client.ListDirectoryAsync(SSH_FOLDER, cancellationToken).ToListAsync(cancellationToken)).Any(x => x.Name == AUTHORIZED_KEYS_FILE);
if (existing_authorized_keys)
{
using (var ms = new MemoryStream())
{
- client.DownloadFile(AUTHORIZED_KEYS_PATH, ms);
+ await client.DownloadFileAsync(AUTHORIZED_KEYS_PATH, ms, cancellationToken).ConfigureAwait(false);
authorized_keys_bytes = ms.ToArray();
authorized_keys = System.Text.Encoding.ASCII.GetString(authorized_keys_bytes);
}
@@ -120,12 +120,12 @@ namespace Duplicati.Library.Backend
{
var filename = AUTHORIZED_KEYS_PATH + ".backup-" + Utility.Utility.SerializeDateTime(DateTime.UtcNow);
using (var ms = new MemoryStream(authorized_keys_bytes))
- client.UploadFile(ms, filename);
+ await client.UploadFileAsync(ms, filename, cancellationToken).ConfigureAwait(false);
client.ChangePermissions(filename, AUTHORIZED_KEYS_BACKUP_PERMISSIONS);
}
using (var ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(new_file)))
- client.UploadFile(ms, AUTHORIZED_KEYS_PATH);
+ await client.UploadFileAsync(ms, AUTHORIZED_KEYS_PATH, cancellationToken).ConfigureAwait(false);
if (!existing_authorized_keys)
client.ChangePermissions(AUTHORIZED_KEYS_PATH, AUTHORIZED_KEYS_PERMISSIONS);
diff --git a/Duplicati/Library/Backend/Storj/StorjConfig.cs b/Duplicati/Library/Backend/Storj/StorjConfig.cs
index 9ba7f762f..11e436ee7 100644
--- a/Duplicati/Library/Backend/Storj/StorjConfig.cs
+++ b/Duplicati/Library/Backend/Storj/StorjConfig.cs
@@ -48,11 +48,11 @@ namespace Duplicati.Library.Backend.Storj
new CommandLineArgument(KEY_CONFIGTYPE, CommandLineArgument.ArgumentType.Enumeration, LC.L("The config to get"), LC.L("Provide different config values"), DEFAULT_CONFIG_TYPE_STR, Enum.GetNames(typeof(ConfigType)))
];
- public IDictionary Execute(IDictionary options)
+ public Task> Execute(IDictionary options, CancellationToken cancellationToken)
{
var ct = Utility.Utility.ParseEnumOption(options.AsReadOnly(), KEY_CONFIGTYPE, DEFAULT_CONFIG_TYPE);
GetLookups().TryGetValue(ct.ToString(), out var dict);
- return dict ?? new Dictionary();
+ return Task.FromResult(dict ?? new Dictionary());
}
public IDictionary> GetLookups()
diff --git a/Duplicati/Library/Interface/IWebModule.cs b/Duplicati/Library/Interface/IWebModule.cs
index 42c957f98..ab59e34a1 100644
--- a/Duplicati/Library/Interface/IWebModule.cs
+++ b/Duplicati/Library/Interface/IWebModule.cs
@@ -20,32 +20,20 @@
// DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
namespace Duplicati.Library.Interface
{
- public interface IWebModule : IDynamicModule
+ public interface IWebModule : ICommonModule
{
- ///
- /// The module key, used to activate or deactivate the module on the commandline
- ///
- string Key { get; }
-
- ///
- /// A localized string describing the module with a friendly name
- ///
- string DisplayName { get; }
-
- ///
- /// A localized description of the module
- ///
- string Description { get; }
-
///
/// Execute the specified command with the given options.
///
/// The options to use
+ /// The cancellation token
/// A list of output values
- IDictionary Execute(IDictionary options);
+ Task> Execute(IDictionary options, CancellationToken cancellationToken);
///
/// Returns lookup data from the module, if any.
diff --git a/Duplicati/WebserverCore/Endpoints/V1/WebModules.cs b/Duplicati/WebserverCore/Endpoints/V1/WebModules.cs
index 363ee6833..4292f5903 100644
--- a/Duplicati/WebserverCore/Endpoints/V1/WebModules.cs
+++ b/Duplicati/WebserverCore/Endpoints/V1/WebModules.cs
@@ -63,7 +63,7 @@ public record WebModules : IEndpointV1
return new Dto.WebModuleOutputDto(
Status: "OK",
- Result: m.Execute(options)
+ Result: await m.Execute(options, cancellationToken).ConfigureAwait(false)
);
}