This PR adds a single API endpoint for listing contents of remote source or backend. With this API, we can greatly simplify the FE as it does not need to know about webmodules for each provider, but can just use the single API. To support this, the fulldisk module was updated slightly to return enumerable meta entries, similar to ms365 and gws providers.
92 lines
4.0 KiB
C#
92 lines
4.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Duplicati.Library.Interface;
|
|
using Duplicati.Library.Logging;
|
|
using Duplicati.Library.Utility;
|
|
using Duplicati.Proprietary.DiskImage.General;
|
|
|
|
namespace Duplicati.Proprietary.DiskImage;
|
|
|
|
public class WebModule : IWebModule
|
|
{
|
|
private static readonly string LOGTAG = Log.LogTagFromType<WebModule>();
|
|
|
|
public string Key => OptionsHelper.ModuleKey;
|
|
|
|
public string DisplayName => Strings.WebModuleDisplayName;
|
|
|
|
public string Description => Strings.WebModuleDescription;
|
|
|
|
public enum Operation
|
|
{
|
|
ListDestination
|
|
}
|
|
|
|
private static readonly Operation DEFAULT_OPERATION = Operation.ListDestination;
|
|
private const string KEY_OPERATION = "operation";
|
|
private const string KEY_URL = "url";
|
|
private const string KEY_PATH = "path";
|
|
|
|
public IList<ICommandLineArgument> SupportedCommands => [
|
|
new CommandLineArgument(KEY_OPERATION, CommandLineArgument.ArgumentType.Enumeration, Strings.WebModuleOperationShort, Strings.WebModuleOperationLong, DEFAULT_OPERATION.ToString(), null, Enum.GetNames<Operation>()),
|
|
new CommandLineArgument(KEY_URL, CommandLineArgument.ArgumentType.String, Strings.WebModuleURLShort, Strings.WebModuleURLLong),
|
|
new CommandLineArgument(KEY_PATH, CommandLineArgument.ArgumentType.String, Strings.WebModulePathShort, Strings.WebModulePathLong)
|
|
];
|
|
|
|
public async Task<IDictionary<string, string>> Execute(IDictionary<string, string?> options, CancellationToken cancellationToken)
|
|
{
|
|
var op = Utility.ParseEnumOption(options.AsReadOnly(), KEY_OPERATION, DEFAULT_OPERATION);
|
|
options.TryGetValue(KEY_PATH, out var path);
|
|
|
|
if (op != Operation.ListDestination)
|
|
throw new UserInformationException($"Unsupported operation: {op}", "UnsupportedOperation");
|
|
|
|
if (string.IsNullOrWhiteSpace(path) || path == "/")
|
|
{
|
|
var res = new Dictionary<string, string>();
|
|
await foreach (var drive in SourceProvider.ListPhysicalDrives(cancellationToken))
|
|
res[drive.Path] = JsonSerializer.Serialize(await drive.GetMinorMetadata(cancellationToken));
|
|
|
|
return res;
|
|
}
|
|
|
|
var prefix = SourceProvider.GetDevicePrefix();
|
|
List<string> parts = [.. path[prefix.Length..].Split(Path.DirectorySeparatorChar, 2)];
|
|
var physicalDrivePath = prefix + parts.First();
|
|
var subpath = parts.Last();
|
|
|
|
using var client = new SourceProvider("diskimage://" + physicalDrivePath, "", new Dictionary<string, string?>(options));
|
|
await client.InitializeAsync(cancellationToken);
|
|
|
|
if (string.IsNullOrWhiteSpace(subpath))
|
|
return new Dictionary<string, string>()
|
|
{
|
|
{$"{physicalDrivePath}{Path.DirectorySeparatorChar}root{Path.DirectorySeparatorChar}", "{}"}
|
|
};
|
|
|
|
var targetEntry = await client.GetEntryAsync(subpath, isFolder: true, cancellationToken).ConfigureAwait(false)
|
|
?? throw new DirectoryNotFoundException($"Path not found: {path}");
|
|
|
|
var result = new Dictionary<string, string>();
|
|
await foreach (var entry in targetEntry.Enumerate(cancellationToken))
|
|
{
|
|
if (entry.Path.EndsWith("geometry.json", StringComparison.OrdinalIgnoreCase))
|
|
continue;
|
|
var metadata = await entry.GetMinorMetadata(cancellationToken);
|
|
if (metadata.ContainsKey("partition:Number"))
|
|
result[$"{physicalDrivePath}{Path.DirectorySeparatorChar}{entry.Path.TrimEnd(Path.DirectorySeparatorChar)}"] = JsonSerializer.Serialize(metadata);
|
|
else
|
|
result[$"{physicalDrivePath}{Path.DirectorySeparatorChar}{entry.Path}"] = JsonSerializer.Serialize(metadata);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public IDictionary<string, IDictionary<string, string>> GetLookups()
|
|
=> new Dictionary<string, IDictionary<string, string>>();
|
|
} |