Skip to content

[Help Wanted] dev/lubl/file-enum #12601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Files.App.Storage/Files.App.Storage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
<Configurations>Debug;Release;Stable;Preview;Store</Configurations>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageReference Include="FluentFTP">
<Version>43.0.1</Version>
</PackageReference>
<PackageReference Include="Vanara.Windows.Shell" Version="3.4.15" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Files.Sdk.Storage\Files.Sdk.Storage.csproj" />
Expand Down
21 changes: 20 additions & 1 deletion src/Files.App.Storage/FtpStorage/FtpHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Files.App.Storage.FtpStorage
{
internal static class FtpHelpers
public static class FtpHelpers
{
public static string GetFtpPath(string path)
{
Expand All @@ -26,6 +26,25 @@ public static Task EnsureConnectedAsync(this AsyncFtpClient ftpClient, Cancellat
return ftpClient.IsConnected ? Task.CompletedTask : ftpClient.Connect(cancellationToken);
}

public static bool IsFtpPath(string path)
{
if (!string.IsNullOrEmpty(path))
{
return path.StartsWith("ftp://", StringComparison.OrdinalIgnoreCase)
|| path.StartsWith("ftps://", StringComparison.OrdinalIgnoreCase)
|| path.StartsWith("ftpes://", StringComparison.OrdinalIgnoreCase);
}
return false;
}

public static bool VerifyFtpPath(string path)
{
var authority = GetFtpAuthority(path);
var index = authority.IndexOf(':', StringComparison.Ordinal);

return index == -1 || ushort.TryParse(authority.Substring(index + 1), out _);
}

public static string GetFtpHost(string path)
{
var authority = GetFtpAuthority(path);
Expand Down
40 changes: 40 additions & 0 deletions src/Files.App.Storage/FtpStorage/FtpStorageFolder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.

using Files.App.Storage.NativeStorage;
using Files.Sdk.Storage;
using Files.Sdk.Storage.Enums;
using Files.Sdk.Storage.Extensions;
Expand All @@ -11,6 +12,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -197,5 +199,43 @@ public async Task<IFolder> CreateFolderAsync(string desiredName, CreationCollisi

return new FtpStorageFolder(newPath, desiredName);
}

public async IAsyncEnumerable<IStorable> SearchAsync(string userQuery, SearchDepth depth = SearchDepth.Shallow)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be an extension method?

{
List<IStorable> results = new List<IStorable>();

if (depth == SearchDepth.Deep)
{
async Task<IStorable> SearchInternalAsync(FtpStorageFolder folder)
{
await foreach (IStorable item in folder.GetItemsAsync(StorableKind.All))
{
if (item is FtpStorageFolder folderChild)
{
results.Add(await SearchInternalAsync(folderChild));
return item;
}
else
{
return item;
}
}
return folder;
}
await SearchInternalAsync(this);
}
else
{
await foreach (var item in GetItemsAsync(StorableKind.All))
{
results.Add(item);
}
}

foreach (var item in results.Where(x => x.Name.Contains(userQuery)))
{
yield return item;
}
}
}
}
41 changes: 40 additions & 1 deletion src/Files.App.Storage/NativeStorage/NativeFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -201,5 +202,43 @@ public Task<IFolderWatcher> GetFolderWatcherAsync(CancellationToken cancellation
{
return Task.FromResult<IFolderWatcher>(new NativeFolderWatcher(this));
}
}

public async IAsyncEnumerable<IStorable> SearchAsync(string userQuery, SearchDepth depth = SearchDepth.Shallow)
{
List<IStorable> results = new List<IStorable>();

if (depth == SearchDepth.Deep)
{
async Task<IStorable> SearchInternalAsync(NativeFolder folder)
{
await foreach (IStorable item in folder.GetItemsAsync(StorableKind.All))
{
if (item is NativeFolder folderChild)
{
results.Add(await SearchInternalAsync(folderChild));
return item;
}
else
{
return item;
}
}
return folder;
}
await SearchInternalAsync(this);
}
else
{
await foreach (var item in GetItemsAsync(StorableKind.All))
{
results.Add(item);
}
}

foreach (var item in results.Where(x => x.Name.Contains(userQuery)))
{
yield return item;
}
}
}
}
28 changes: 27 additions & 1 deletion src/Files.App.Storage/NativeStorage/NativeFolderWatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Files.Sdk.Storage.LocatableStorage;
using Files.Sdk.Storage.MutableStorage;
using System;
using System.Collections.Specialized;
using System.IO;
using System.Threading.Tasks;
Expand All @@ -15,6 +16,11 @@ public sealed class NativeFolderWatcher : IFolderWatcher
private FileSystemWatcher? _fileSystemWatcher;
private NotifyCollectionChangedEventHandler? _collectionChanged;

public event EventHandler<FileSystemEventArgs> ItemAdded;
public event EventHandler<FileSystemEventArgs> ItemRemoved;
public event EventHandler<FileSystemEventArgs> ItemChanged;
public event EventHandler<RenamedEventArgs> ItemRenamed;

public IMutableFolder Folder { get; }

/// <inheritdoc/>
Expand All @@ -39,32 +45,41 @@ public event NotifyCollectionChangedEventHandler? CollectionChanged
public NativeFolderWatcher(IMutableFolder folder)
{
Folder = folder;
SetupWatcher();
}

private void SetupWatcher()
{
if (Folder is ILocatableFolder locatableFolder)
{
_fileSystemWatcher = new(locatableFolder.Path);
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.Created += FileSystemWatcher_Created;
_fileSystemWatcher.Deleted += FileSystemWatcher_Deleted;
_fileSystemWatcher.Renamed += FileSystemWatcher_Renamed;
}
}

private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
ItemChanged?.Invoke(sender, e);
_collectionChanged?.Invoke(this, new(NotifyCollectionChangedAction.Replace, e));
}

private void FileSystemWatcher_Renamed(object sender, RenamedEventArgs e)
{
ItemRenamed?.Invoke(sender, e);
_collectionChanged?.Invoke(this, new(NotifyCollectionChangedAction.Replace, e.FullPath, e.OldFullPath));
}

private void FileSystemWatcher_Deleted(object sender, FileSystemEventArgs e)
{
ItemRemoved?.Invoke(sender, e);
_collectionChanged?.Invoke(this, new(NotifyCollectionChangedAction.Remove, e.FullPath));
}

private void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
ItemAdded?.Invoke(sender, e);
_collectionChanged?.Invoke(this, new(NotifyCollectionChangedAction.Add, e.FullPath));
}

Expand All @@ -81,11 +96,22 @@ public void Dispose()
if (_fileSystemWatcher is not null)
{
_fileSystemWatcher.EnableRaisingEvents = false;
_fileSystemWatcher.Changed -= FileSystemWatcher_Changed;
_fileSystemWatcher.Created -= FileSystemWatcher_Created;
_fileSystemWatcher.Deleted -= FileSystemWatcher_Deleted;
_fileSystemWatcher.Renamed -= FileSystemWatcher_Renamed;
_fileSystemWatcher.Dispose();
}
}

public void Start()
{
SetupWatcher();
}

public void Stop()
{
Dispose();
}
}
}
18 changes: 18 additions & 0 deletions src/Files.App.Storage/StorableViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.

using CommunityToolkit.Mvvm.ComponentModel;
using Files.Sdk.Storage;

namespace Files.App.Storage
{
public abstract class StorableViewModel : ObservableObject
{
public IStorable Storable { get; }

public StorableViewModel(IStorable storable)
{
this.Storable = storable;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Files.App.Storage.WindowsStorage.Win32.Helpers
{
public class AsyncManualResetEvent
{
private volatile TaskCompletionSource<bool> m_tcs = new TaskCompletionSource<bool>();

public async Task WaitAsync(CancellationToken cancellationToken = default)
{
var tcs = m_tcs;
var cancelTcs = new TaskCompletionSource<bool>();

cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s!).TrySetCanceled(), cancelTcs);

await await Task.WhenAny(tcs.Task, cancelTcs.Task);
}

private async Task<bool> Delay(int milliseconds)
{
await Task.Delay(milliseconds);
return false;
}

public async Task<bool> WaitAsync(int milliseconds, CancellationToken cancellationToken = default)
{
var tcs = m_tcs;
var cancelTcs = new TaskCompletionSource<bool>();

cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s!).TrySetCanceled(), cancelTcs);

return await await Task.WhenAny(tcs.Task, cancelTcs.Task, Delay(milliseconds));
}

public void Set()
{
var tcs = m_tcs;
Task.Factory.StartNew(s => ((TaskCompletionSource<bool>)s!).TrySetResult(true),
tcs, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default);
tcs.Task.Wait();
}

public void Reset()
{
var newTcs = new TaskCompletionSource<bool>();
while (true)
{
var tcs = m_tcs;
if (!tcs.Task.IsCompleted ||
Interlocked.CompareExchange(ref m_tcs, newTcs, tcs) == tcs)
return;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.

using System;

namespace Files.App.Storage.WindowsStorage.Win32.Helpers
{
internal class IntervalSampler
{
private DateTime recordPoint;
private TimeSpan sampleInterval;

public IntervalSampler(int millisecondsInterval)
{
sampleInterval = TimeSpan.FromMilliseconds(millisecondsInterval);
recordPoint = DateTime.Now;
}

public IntervalSampler(TimeSpan interval)
{
sampleInterval = interval;
recordPoint = DateTime.Now;
}

public void Reset()
{
recordPoint = DateTime.Now;
}

public bool CheckNow()
{
var now = DateTime.Now;
if (now - sampleInterval >= recordPoint)
{
recordPoint = now;
return true;
}
return false;
}
}
}
Loading