Add settings, cloud places, and optional archive-content indexing.
Keep official clients in charge of sync while Explorer can group locations, persist UI prefs, and list zip/rar/7z members without extracting them. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using Explorer.Application;
|
||||
using Explorer.Domain;
|
||||
using Explorer.Domain.Abstractions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Explorer.Indexing;
|
||||
|
||||
@@ -10,12 +9,18 @@ public sealed class FolderReconciler
|
||||
private readonly IIndexStore _store;
|
||||
private readonly IFileSystemEnumerator _enumerator;
|
||||
private readonly StorageProviderRegistry _providers;
|
||||
private readonly ArchiveContentsIndexer? _archives;
|
||||
|
||||
public FolderReconciler(IIndexStore store, IFileSystemEnumerator enumerator, StorageProviderRegistry providers)
|
||||
public FolderReconciler(
|
||||
IIndexStore store,
|
||||
IFileSystemEnumerator enumerator,
|
||||
StorageProviderRegistry providers,
|
||||
ArchiveContentsIndexer? archives = null)
|
||||
{
|
||||
_store = store;
|
||||
_enumerator = enumerator;
|
||||
_providers = providers;
|
||||
_archives = archives;
|
||||
}
|
||||
|
||||
public async Task ReconcileAsync(Source source, string pathRel, CancellationToken cancellationToken)
|
||||
@@ -32,12 +37,38 @@ public sealed class FolderReconciler
|
||||
return;
|
||||
}
|
||||
|
||||
if (!parent.IsDirectory)
|
||||
{
|
||||
if (ArchiveFormats.IsArchive(parent.Name))
|
||||
{
|
||||
if (_archives is { IsEnabled: true } && File.Exists(full))
|
||||
{
|
||||
await _archives.ExpandIfNeededAsync(source, parent, DateTimeOffset.UtcNow, source.ScanGeneration, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _store.Entries.TombstoneByPathPrefixAsync(source.Id, parent.PathRel, DateTimeOffset.UtcNow, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(full))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var live = await _providers.EnrichAsync(_enumerator.EnumerateChildrenSafe(full, out _), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var indexed = await _store.Entries.GetChildrenAsync(source.Id, parent.Id, EntryStatus.Present, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var liveNames = new HashSet<string>(live.Select(i => NameNormalizer.Normalize(i.Name)), StringComparer.Ordinal);
|
||||
var archivesToExpand = new List<IndexEntry>();
|
||||
var archivesToTomb = new List<string>();
|
||||
|
||||
await _store.RunWriteAsync(async s =>
|
||||
{
|
||||
@@ -71,6 +102,7 @@ public sealed class FolderReconciler
|
||||
var existing = indexed.FirstOrDefault(e => e.NameNorm == entry.NameNorm);
|
||||
var oldSize = existing is { IsDirectory: false } ? existing.SizeBytes : 0;
|
||||
var id = await s.Entries.UpsertAsync(entry, cancellationToken).ConfigureAwait(false);
|
||||
entry.Id = id;
|
||||
if (!item.IsDirectory)
|
||||
{
|
||||
var delta = item.SizeBytes - oldSize;
|
||||
@@ -84,14 +116,17 @@ public sealed class FolderReconciler
|
||||
await s.Entries.ApplySizeDeltaToAncestorsAsync(parent.Id, delta, 0, 0, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (ArchiveFormats.IsArchive(item.Name))
|
||||
{
|
||||
archivesToExpand.Add(entry);
|
||||
}
|
||||
}
|
||||
else if (existing is null)
|
||||
{
|
||||
await s.Entries.ApplySizeDeltaToAncestorsAsync(parent.Id, 0, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_ = id;
|
||||
}
|
||||
|
||||
foreach (var old in indexed)
|
||||
@@ -99,8 +134,27 @@ public sealed class FolderReconciler
|
||||
if (!liveNames.Contains(old.NameNorm))
|
||||
{
|
||||
await s.Entries.TombstoneAsync(old.Id, now, cancellationToken).ConfigureAwait(false);
|
||||
if (!old.IsDirectory && ArchiveFormats.IsArchive(old.Name))
|
||||
{
|
||||
archivesToTomb.Add(old.PathRel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var path in archivesToTomb)
|
||||
{
|
||||
await _store.Entries.TombstoneByPathPrefixAsync(source.Id, path, now, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (_archives is { IsEnabled: true })
|
||||
{
|
||||
foreach (var archive in archivesToExpand)
|
||||
{
|
||||
await _archives.ExpandIfNeededAsync(source, archive, now, source.ScanGeneration, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user