Add Explorer Workbench with hierarchical, off-UI Storage analysis.
Storage queries run in the background with cancellation and covering indexes so switching views no longer freezes the UI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
140
src/Explorer.Plugin.OneDrive/OneDriveStorageProvider.cs
Normal file
140
src/Explorer.Plugin.OneDrive/OneDriveStorageProvider.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using Explorer.Plugin.Abstractions;
|
||||
using Explorer.Windows;
|
||||
|
||||
namespace Explorer.Plugin.OneDrive;
|
||||
|
||||
public sealed class OneDriveStorageProvider : IStorageProvider
|
||||
{
|
||||
public const string ProviderId = "onedrive";
|
||||
|
||||
private readonly object _gate = new();
|
||||
private IReadOnlyList<ProviderPlace>? _places;
|
||||
|
||||
public ProviderManifest Manifest { get; } = new(
|
||||
ProviderId,
|
||||
"OneDrive",
|
||||
"1.0.0",
|
||||
ProviderIsolation.InProcess);
|
||||
|
||||
public ProviderCapability GetCapabilities()
|
||||
=> ProviderCapability.CloudState | ProviderCapability.Pin | ProviderCapability.Dehydrate;
|
||||
|
||||
public bool TryMatchRoot(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var root in GetPlaces())
|
||||
{
|
||||
if (IsUnder(root.Path, path))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return CloudFilesNative.IsCloudSyncRoot(path);
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<ProviderItemState>> GetItemStatesAsync(
|
||||
IReadOnlyList<string> paths,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var results = new List<ProviderItemState>(paths.Count);
|
||||
foreach (var path in paths)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (!TryMatchRoot(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var attrs = (int)File.GetAttributes(path);
|
||||
var isDir = (attrs & (int)FileAttributes.Directory) != 0;
|
||||
long logical = 0;
|
||||
if (!isDir)
|
||||
{
|
||||
try { logical = new FileInfo(path).Length; } catch { /* locked */ }
|
||||
}
|
||||
|
||||
var allocated = CloudFilesNative.TryGetAllocatedSize(path);
|
||||
var placeholder = CloudFilesNative.TryGetPlaceholderState(attrs, 0);
|
||||
results.Add(OneDrivePlaceholderState.FromLocalSignals(
|
||||
ProviderId, path, attrs, 0, logical, allocated, placeholder));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// fail-open for this item
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult<IReadOnlyList<ProviderItemState>>(results);
|
||||
}
|
||||
|
||||
public Task<ProviderActionResult> TryInvokeAsync(ProviderActionRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var capabilities = GetCapabilities();
|
||||
var needed = request.Action switch
|
||||
{
|
||||
ProviderAction.Pin or ProviderAction.Unpin => ProviderCapability.Pin,
|
||||
ProviderAction.Dehydrate => ProviderCapability.Dehydrate,
|
||||
_ => ProviderCapability.None
|
||||
};
|
||||
|
||||
if (needed == ProviderCapability.None || (capabilities & needed) == 0)
|
||||
{
|
||||
return Task.FromResult(new ProviderActionResult(ProviderActionStatus.Unsupported, "This action is not available."));
|
||||
}
|
||||
|
||||
var pin = request.Action switch
|
||||
{
|
||||
ProviderAction.Pin => CloudFilesNative.PinPinned,
|
||||
ProviderAction.Unpin or ProviderAction.Dehydrate => CloudFilesNative.PinUnpinned,
|
||||
_ => CloudFilesNative.PinUnspecified
|
||||
};
|
||||
|
||||
var failed = 0;
|
||||
foreach (var path in request.Paths)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (!CloudFilesNative.TrySetPinState(path, pin))
|
||||
{
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed == 0)
|
||||
{
|
||||
return Task.FromResult(new ProviderActionResult(ProviderActionStatus.Succeeded));
|
||||
}
|
||||
|
||||
if (failed == request.Paths.Count)
|
||||
{
|
||||
return Task.FromResult(new ProviderActionResult(ProviderActionStatus.Failed, "OneDrive could not change the pin state."));
|
||||
}
|
||||
|
||||
return Task.FromResult(new ProviderActionResult(ProviderActionStatus.Failed, $"OneDrive could not change the pin state for {failed} item(s)."));
|
||||
}
|
||||
|
||||
public Task<ProviderQuota?> TryGetQuotaAsync(string rootPath, CancellationToken cancellationToken = default)
|
||||
=> Task.FromResult<ProviderQuota?>(null);
|
||||
|
||||
public IReadOnlyList<ProviderPlace> GetPlaces()
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
return _places ??= OneDrivePlaceDiscovery.Discover();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsUnder(string root, string path)
|
||||
{
|
||||
var a = root.TrimEnd('\\');
|
||||
var b = path.TrimEnd('\\');
|
||||
return b.Equals(a, StringComparison.OrdinalIgnoreCase)
|
||||
|| b.StartsWith(a + "\\", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user