ContentProvider refactor

This commit is contained in:
2022-02-19 23:00:37 +01:00
parent 13a021c030
commit cd04e992f1
16 changed files with 189 additions and 383 deletions

View File

@@ -1,3 +1,4 @@
using System.Reflection.Metadata;
using AsyncEvent;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
@@ -80,11 +81,14 @@ namespace FileTime.Core.Command.Delete
if (_deleteContainer != null) await _deleteContainer.Invoke(container);
}
else
{
if (container.AllowRecursiveDeletion)
{
foreach (var child in (await container.GetItems())!)
{
await TraverseTree(child);
}
}
if (_deleteContainer != null) await _deleteContainer.Invoke(container);
}

View File

@@ -8,6 +8,7 @@ namespace FileTime.Core.Models
Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default);
Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default);
Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default);
bool AllowRecursiveDeletion { get; }
Task RefreshAsync(CancellationToken token = default);
public async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)

View File

@@ -38,6 +38,7 @@ namespace FileTime.Core.Models
public bool IsDestroyed => BaseContainer.IsDestroyed;
public bool IsExists => BaseContainer.IsExists;
public bool AllowRecursiveDeletion => BaseContainer.AllowRecursiveDeletion;
private void RefreshAddBase(Func<object?, AsyncEventArgs, CancellationToken, Task> handler)
{

View File

@@ -3,9 +3,9 @@ using FileTime.Core.Models;
namespace FileTime.Core.Providers
{
public abstract class AbstractContainer<TProvider> : IContainer where TProvider : IContentProvider
public abstract class AbstractContainer<TProvider> : IContainer where TProvider : class, IContentProvider
{
private readonly IContainer _parent;
private readonly IContainer? _parent;
private readonly List<Exception> _exceptions = new();
private IReadOnlyList<IContainer>? _containers;
private IReadOnlyList<IItem>? _items;
@@ -39,13 +39,26 @@ namespace FileTime.Core.Providers
public abstract bool IsExists { get; }
protected AbstractContainer(TProvider provider, IContainer parent, string name)
public virtual bool AllowRecursiveDeletion { get; protected set; }
protected AbstractContainer(TProvider provider, IContainer parent, string name) : this(name)
{
_parent = parent;
Provider = provider;
FullName = parent.FullName == null ? name : parent.FullName + Constants.SeparatorChar + name;
}
protected AbstractContainer(string name, string? fullName = null) : this(name)
{
Provider = this is TProvider provider ? provider : throw new ArgumentException($"This constructor is for {nameof(IContentProvider)}s only");
FullName = fullName;
}
private AbstractContainer(string name)
{
Name = name;
FullName = parent.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
Exceptions = _exceptions.AsReadOnly();
Provider = null!;
}
public virtual Task<bool> CanOpenAsync() => Task.FromResult(_exceptions.Count == 0);

View File

@@ -0,0 +1,122 @@
using AsyncEvent;
using FileTime.Core.Models;
namespace FileTime.Core.Providers
{
public abstract class ContentProviderBase<T> : AbstractContainer<T>, IContentProvider
where T : class, IContentProvider
{
private readonly object _initializationGuard = new();
private bool _initialized;
private bool _initializing;
private IContainer? _parent;
protected IReadOnlyList<IContainer>? RootContainers { get; private set; }
public override bool IsExists => true;
protected ContentProviderBase(
string name,
string? fullName,
string protocol,
bool supportsContentStreams)
: base(name, fullName)
{
Protocol = protocol;
SupportsContentStreams = supportsContentStreams;
CanRename = false;
CanDelete = SupportsDelete.False;
}
public virtual bool SupportsContentStreams { get; }
public virtual string Protocol { get; }
public abstract Task<bool> CanHandlePath(string path);
public override IContainer? GetParent() => _parent;
public void SetParent(IContainer parent) => _parent = parent;
protected async Task AddRootContainer(IContainer newRootContainer)
{
RootContainers =
(await GetContainers())?.Append(newRootContainer).OrderBy(c => c.Name).ToList().AsReadOnly()
?? new List<IContainer>() { newRootContainer }.AsReadOnly();
}
protected async Task AddRootContainers(IEnumerable<IContainer> newRootContainers)
{
RootContainers =
(await GetContainers())?.Concat(newRootContainers).OrderBy(c => c.Name).ToList().AsReadOnly()
?? new List<IContainer>(newRootContainers).AsReadOnly();
}
protected void SetRootContainers(IEnumerable<IContainer> newRootContainers)
=> RootContainers = newRootContainers.OrderBy(c => c.Name).ToList().AsReadOnly();
public override async Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default)
{
await InitIfNeeded();
return RootContainers;
}
public override async Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default)
{
await InitIfNeeded();
return new List<IElement>();
}
public override async Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
{
await InitIfNeeded();
return RootContainers;
}
private async Task InitIfNeeded()
{
while (true)
{
lock (_initializationGuard)
{
if (!_initializing)
{
_initializing = true;
break;
}
}
await Task.Delay(1);
}
try
{
if (_initialized) return;
_initialized = true;
await Init();
IsLoaded = true;
}
finally
{
lock (_initializationGuard)
{
_initializing = false;
}
}
}
protected virtual Task Init() { return Task.CompletedTask; }
public override Task<IEnumerable<IItem>> RefreshItems(CancellationToken token = default) { throw new NotImplementedException($"{nameof(RefreshItems)} should not be called in {nameof(ContentProviderBase<T>)}."); }
public override Task<bool> IsExistsAsync(string name) => Task.FromResult(RootContainers?.Any(i => i.Name == name) ?? false);
public override async Task RefreshAsync(CancellationToken token = default) => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty, token);
public override Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
public override Task Delete(bool hardDelete = false) => throw new NotSupportedException();
public override Task Rename(string newName) => throw new NotSupportedException();
public override Task<bool> CanOpenAsync() => Task.FromResult(true);
public override void Unload() { }
public override void Destroy() { }
}
}

View File

@@ -7,9 +7,7 @@ namespace FileTime.Core.Providers
bool SupportsContentStreams { get; }
string Protocol { get; }
Task<IReadOnlyList<IContainer>> GetRootContainers(CancellationToken token = default);
bool CanHandlePath(string path);
Task<bool> CanHandlePath(string path);
void SetParent(IContainer container);
}

View File

@@ -34,6 +34,7 @@ namespace FileTime.Core.Providers
public bool IsDestroyed => false;
public bool IsExists => true;
public bool AllowRecursiveDeletion => false;
public TopContainer(IEnumerable<IContentProvider> contentProviders)
{

View File

@@ -34,6 +34,7 @@ namespace FileTime.Core.Timeline
//FIXME: currently this can be different of the real items NativePath, should be fixed
public string? NativePath => FullName;
public bool IsExists => true;
public bool AllowRecursiveDeletion => true;
public TimeContainer(string name, IContainer parent, IContentProvider contentProvider, IContentProvider virtualContentProvider, PointInTime pointInTime)
{

View File

@@ -1,115 +1,30 @@
using AsyncEvent;
using FileTime.Core.Models;
using FileTime.Core.Providers;
namespace FileTime.Core.Timeline
{
public class TimeProvider : IContentProvider
public class TimeProvider : ContentProviderBase<TimeProvider>
{
private readonly PointInTime _pointInTime;
public bool IsLoaded => true;
public AsyncEventHandler Refreshed { get; } = new();
public string Name => "time";
public string? FullName => null;
public string? NativePath => null;
public bool IsHidden => false;
public SupportsDelete CanDelete => SupportsDelete.False;
public bool CanRename => false;
public IContentProvider Provider => this;
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
public bool SupportsDirectoryLevelSoftDelete => false;
public bool IsDestroyed => false;
public bool SupportsContentStreams => false;
public string Protocol => "time2://";
public bool IsExists => true;
public TimeProvider(PointInTime pointInTime)
public TimeProvider(PointInTime pointInTime) : base("time", null, "time2://", false)
{
_pointInTime = pointInTime;
}
public bool CanHandlePath(string path)
public override Task<bool> CanHandlePath(string path)
{
throw new NotImplementedException();
}
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
public Task<IContainer> CreateContainerAsync(string name)
public override Task<IContainer> CreateContainerAsync(string name)
{
throw new NotImplementedException();
}
public Task<IElement> CreateElementAsync(string name)
public override Task<IElement> CreateElementAsync(string name)
{
throw new NotImplementedException();
}
public Task Delete(bool hardDelete = false) => throw new NotSupportedException();
public Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
{
throw new NotImplementedException();
}
public Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default)
{
throw new NotImplementedException();
}
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default)
{
throw new NotImplementedException();
}
public Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
{
throw new NotImplementedException();
}
public IContainer? GetParent() => null;
public Task<IReadOnlyList<IContainer>> GetRootContainers(CancellationToken token = default)
{
throw new NotImplementedException();
}
public Task<bool> IsExistsAsync(string name)
{
throw new NotImplementedException();
}
public Task RefreshAsync(CancellationToken token = default) => Task.CompletedTask;
public Task Rename(string newName) => throw new NotSupportedException();
public void SetParent(IContainer container) { }
public Task<bool> CanOpenAsync() => Task.FromResult(true);
public void Destroy() { }
public void Unload() { }
public Task<IContentReader> GetContentReaderAsync(IElement element)
{
throw new NotSupportedException();
}
public Task<IContentWriter> GetContentWriterAsync(IElement element)
{
throw new NotSupportedException();
}
}
}

View File

@@ -564,7 +564,7 @@ namespace FileTime.Avalonia.Services
var path = inputs[0].Value;
foreach (var contentProvider in _contentProviders)
{
if (contentProvider.CanHandlePath(path))
if (await contentProvider.CanHandlePath(path))
{
var possibleContainer = await contentProvider.GetByPath(path);
if (possibleContainer is IContainer container)

View File

@@ -121,7 +121,7 @@ namespace FileTime.Avalonia.Services
{
foreach (var contentProvider in _contentProviders)
{
if (contentProvider.CanHandlePath(tab.Path))
if (await contentProvider.CanHandlePath(tab.Path))
{
pathItem = await contentProvider.GetByPath(tab.Path, true);
if (pathItem != null) break;

View File

@@ -235,7 +235,7 @@ namespace FileTime.Avalonia.ViewModels
private async Task<IContainer?> GetContainerForWindowsDrive(DriveInfo drive)
{
return (await LocalContentProvider.GetRootContainers()).FirstOrDefault(d => d.Name == drive.Name.TrimEnd(Path.DirectorySeparatorChar));
return (await LocalContentProvider.GetContainers())!.FirstOrDefault(d => d.Name == drive.Name.TrimEnd(Path.DirectorySeparatorChar));
}
private async Task<IContainer?> GetContainerForLinuxDrive(DriveInfo drive)

View File

@@ -1,46 +1,17 @@
using System.Threading.Tasks;
using System;
using System.Runtime.InteropServices;
using AsyncEvent;
using FileTime.Core.Models;
using FileTime.Core.Providers;
using Microsoft.Extensions.Logging;
namespace FileTime.Providers.Local
{
public class LocalContentProvider : IContentProvider
public class LocalContentProvider : ContentProviderBase<LocalContentProvider>
{
private readonly ILogger<LocalContentProvider> _logger;
private IContainer? _parent;
private readonly IReadOnlyList<IContainer> _rootContainers;
private readonly IReadOnlyList<IItem>? _items;
private readonly IReadOnlyList<IElement>? _elements = new List<IElement>().AsReadOnly();
public string Name { get; } = "local";
public string Protocol { get; } = "local://";
public string? FullName { get; }
public string? NativePath => null;
public bool IsHidden => false;
public bool IsLoaded => true;
public IContentProvider Provider => this;
public AsyncEventHandler Refreshed { get; } = new();
public bool IsCaseInsensitive { get; }
public SupportsDelete CanDelete => SupportsDelete.False;
public bool CanRename => false;
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
public bool SupportsDirectoryLevelSoftDelete => false;
public bool IsDestroyed => false;
public bool SupportsContentStreams => true;
public bool IsExists => true;
public LocalContentProvider(ILogger<LocalContentProvider> logger)
: base("local", null, "local://", true)
{
_logger = logger;
@@ -50,8 +21,7 @@ namespace FileTime.Providers.Local
? new DirectoryInfo("/").GetDirectories()
: Environment.GetLogicalDrives().Select(d => new DirectoryInfo(d));
_rootContainers = rootDirectories.Select(d => new LocalFolder(d, this, this)).OrderBy(d => d.Name).ToList().AsReadOnly();
_items = _rootContainers.Cast<IItem>().ToList().AsReadOnly();
SetRootContainers(rootDirectories.Select(d => new LocalFolder(d, this, this)).OrderBy(d => d.Name));
}
public async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
@@ -62,11 +32,11 @@ namespace FileTime.Providers.Local
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && pathParts.Length == 1 && pathParts[0]?.Length == 0) return this;
var normalizedRootContainerName = NormalizePath(pathParts[0]);
var rootContainer = _rootContainers.FirstOrDefault(c => NormalizePath(c.Name) == normalizedRootContainerName);
var rootContainer = RootContainers?.FirstOrDefault(c => NormalizePath(c.Name) == normalizedRootContainerName);
if (rootContainer == null)
{
_logger.LogWarning("No root container found with name '{RootContainerName}'", path[0]);
_logger.LogWarning("No root container found with name '{RootContainerName}'.", path[0]);
return null;
}
@@ -74,52 +44,18 @@ namespace FileTime.Providers.Local
return remainingPath.Length == 0 ? rootContainer : await rootContainer.GetByPath(remainingPath, acceptDeepestMatch);
}
public async Task RefreshAsync(CancellationToken token = default) => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty, token);
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
public IContainer? GetParent() => _parent;
public Task<IContainer> CreateContainerAsync(string name) => throw new NotSupportedException();
public Task<IElement> CreateElementAsync(string name) => throw new NotSupportedException();
public Task<bool> IsExistsAsync(string name) => Task.FromResult(_rootContainers.Any(i => i.Name == name));
public Task Delete(bool hardDelete = false) => throw new NotSupportedException();
public override Task<IContainer> CreateContainerAsync(string name) => throw new NotSupportedException();
public override Task<IElement> CreateElementAsync(string name) => throw new NotSupportedException();
internal string NormalizePath(string path) => IsCaseInsensitive ? path.ToLower() : path;
public bool CanHandlePath(string path)
public override async Task<bool> CanHandlePath(string path)
{
var normalizedPath = NormalizePath(path);
Func<IContainer, bool> match = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? c => normalizedPath.StartsWith(NormalizePath(c.Name))
: c => normalizedPath.StartsWith(NormalizePath("/" + c.Name));
return _rootContainers.Any(match);
}
public void SetParent(IContainer container) => _parent = container;
public Task<IReadOnlyList<IContainer>> GetRootContainers(CancellationToken token = default) => Task.FromResult(_rootContainers);
public Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default) => Task.FromResult(_items);
public Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default) => Task.FromResult((IReadOnlyList<IContainer>?)_rootContainers);
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult(_elements);
public Task Rename(string newName) => throw new NotSupportedException();
public Task<bool> CanOpenAsync() => Task.FromResult(true);
public void Destroy()
{
foreach (var c in _rootContainers)
{
c.Unload();
}
}
public void Unload()
{
foreach (var c in _rootContainers)
{
c.Unload();
}
return (await GetContainers())?.Any(match) ?? false;
}
}
}

View File

@@ -21,6 +21,7 @@ namespace FileTime.Providers.Local
NativePath = Directory.FullName;
IsHidden = (Directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
CanRename = true;
AllowRecursiveDeletion = true;
//TODO: Linux soft delete
SupportsDirectoryLevelSoftDelete = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

View File

@@ -1,4 +1,3 @@
using AsyncEvent;
using FileTime.Core.Interactions;
using FileTime.Core.Models;
using FileTime.Core.Providers;
@@ -6,67 +5,28 @@ using Microsoft.Extensions.Logging;
namespace FileTime.Providers.Sftp
{
public class SftpContentProvider : IContentProvider
public class SftpContentProvider : ContentProviderBase<SftpContentProvider>, IContainer
{
private IContainer? _parent;
private readonly IInputInterface _inputInterface;
private readonly List<IContainer> _rootContainers;
private readonly IReadOnlyList<IContainer> _rootContainersReadOnly;
private IReadOnlyList<IItem>? _items;
private readonly IReadOnlyList<IElement> _elements = new List<IElement>().AsReadOnly();
private readonly ILogger<SftpContentProvider> _logger;
public bool SupportsContentStreams => false;
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
public bool IsLoaded => true;
public bool SupportsDirectoryLevelSoftDelete => false;
public AsyncEventHandler Refreshed { get; } = new AsyncEventHandler();
public string Name => "sftp";
public string? FullName => null;
public string? NativePath => null;
public bool IsHidden => false;
public bool IsDestroyed => false;
public SupportsDelete CanDelete => SupportsDelete.False;
public bool CanRename => false;
public IContentProvider Provider => this;
public string Protocol => "sftp://";
public bool IsExists => true;
public SftpContentProvider(IInputInterface inputInterface, ILogger<SftpContentProvider> logger)
: base("sftp", null, "sftp://", false)
{
_logger = logger;
_rootContainers = new List<IContainer>();
_items = new List<IItem>();
_rootContainersReadOnly = _rootContainers.AsReadOnly();
_inputInterface = inputInterface;
}
public bool CanHandlePath(string path) => path.StartsWith("sftp://");
public Task<bool> CanOpenAsync() => Task.FromResult(true);
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
public override Task<bool> CanHandlePath(string path) => Task.FromResult(path.StartsWith("sftp://"));
public async Task<IContainer> CreateContainerAsync(string name)
public override async Task<IContainer> CreateContainerAsync(string name)
{
var container = _rootContainers.Find(c => c.Name == name);
var container = RootContainers?.FirstOrDefault(c => c.Name == name);
if (container == null)
{
container = new SftpServer(name, this, _inputInterface);
_rootContainers.Add(container);
_items = _rootContainers.OrderBy(c => c.Name).ToList().AsReadOnly();
await AddRootContainer(container);
}
await RefreshAsync();
@@ -76,50 +36,9 @@ namespace FileTime.Providers.Sftp
return container;
}
public Task<IElement> CreateElementAsync(string name)
{
throw new NotSupportedException();
}
public override Task<IElement> CreateElementAsync(string name) => throw new NotSupportedException();
public Task Delete(bool hardDelete = false)
{
throw new NotSupportedException();
}
public void Destroy() { }
public async Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default)
{
await Init();
return _rootContainersReadOnly;
}
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult((IReadOnlyList<IElement>?)_elements);
public async Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
{
await Init();
return _items;
}
public IContainer? GetParent() => _parent;
public Task<IReadOnlyList<IContainer>> GetRootContainers(CancellationToken token = default) => Task.FromResult(_rootContainersReadOnly);
public async Task<bool> IsExistsAsync(string name) => (await GetItems())?.Any(i => i.Name == name) ?? false;
public async Task RefreshAsync(CancellationToken token = default) => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty, token);
public Task Rename(string newName) => throw new NotSupportedException();
public void SetParent(IContainer container) => _parent = container;
public void Unload() { }
private Task Init()
{
return Task.CompletedTask;
}
public async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
async Task<IItem?> IContainer.GetByPath(string path, bool acceptDeepestMatch)
{
if (path == null) return this;

View File

@@ -1,6 +1,4 @@
using System;
using System.Runtime.InteropServices;
using AsyncEvent;
using FileTime.Core.Interactions;
using FileTime.Core.Models;
using FileTime.Core.Providers;
@@ -8,61 +6,28 @@ using Microsoft.Extensions.Logging;
namespace FileTime.Providers.Smb
{
public class SmbContentProvider : IContentProvider
public class SmbContentProvider : ContentProviderBase<SmbContentProvider>, IContainer
{
private readonly object _initializationGuard = new();
private bool _initialized;
private bool _initializing;
private IContainer? _parent;
private readonly IInputInterface _inputInterface;
private readonly List<IContainer> _rootContainers;
private readonly IReadOnlyList<IContainer> _rootContainersReadOnly;
private IReadOnlyList<IItem> _items;
private readonly IReadOnlyList<IElement> _elements = new List<IElement>().AsReadOnly();
private readonly Persistence.PersistenceService _persistenceService;
private readonly ILogger<SmbContentProvider> _logger;
public string Name { get; } = "smb";
public string Protocol { get; } = "smb://";
public string? FullName => null;
public string? NativePath => null;
public bool IsHidden => false;
public bool IsLoaded => true;
public IContentProvider Provider => this;
public SupportsDelete CanDelete => SupportsDelete.False;
public bool CanRename => false;
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
public AsyncEventHandler Refreshed { get; } = new();
public bool SupportsDirectoryLevelSoftDelete => false;
public bool IsDestroyed => false;
public bool SupportsContentStreams => true;
public bool IsExists => true;
public SmbContentProvider(IInputInterface inputInterface, Persistence.PersistenceService persistenceService, ILogger<SmbContentProvider> logger)
: base("smb", null, "smb://", true)
{
_rootContainers = new List<IContainer>();
_items = new List<IItem>();
_rootContainersReadOnly = _rootContainers.AsReadOnly();
_inputInterface = inputInterface;
_persistenceService = persistenceService;
_logger = logger;
}
public async Task<IContainer> CreateContainerAsync(string name)
public override async Task<IContainer> CreateContainerAsync(string name)
{
var container = _rootContainers.Find(c => c.Name == name);
var container = RootContainers?.FirstOrDefault(c => c.Name == name);
if (container == null)
{
container = new SmbServer(name, this, _inputInterface);
_rootContainers.Add(container);
_items = _rootContainers.OrderBy(c => c.Name).ToList().AsReadOnly();
await AddRootContainer(container);
}
await RefreshAsync();
@@ -72,17 +37,9 @@ namespace FileTime.Providers.Smb
return container;
}
public Task<IElement> CreateElementAsync(string name)
{
throw new NotSupportedException();
}
public override Task<IElement> CreateElementAsync(string name) => throw new NotSupportedException();
public Task Delete(bool hardDelete = false)
{
throw new NotSupportedException();
}
public async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
async Task<IItem?> IContainer.GetByPath(string path, bool acceptDeepestMatch)
{
if (path == null) return this;
@@ -117,45 +74,13 @@ namespace FileTime.Providers.Smb
}
}
public IContainer? GetParent() => _parent;
public Task<IContainer> CloneAsync() => Task.FromResult((IContainer)this);
public async Task<bool> IsExistsAsync(string name) => (await GetItems())?.Any(i => i.Name == name) ?? false;
public async Task RefreshAsync(CancellationToken token = default) => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty, token);
public bool CanHandlePath(string path) => path.StartsWith("smb://") || path.StartsWith(@"\\");
public void SetParent(IContainer container) => _parent = container;
public Task<IReadOnlyList<IContainer>> GetRootContainers(CancellationToken token = default) => Task.FromResult(_rootContainersReadOnly);
public async Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
{
await Init();
return _items;
}
public async Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default)
{
await Init();
return _rootContainersReadOnly;
}
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult((IReadOnlyList<IElement>?)_elements);
public Task Rename(string newName) => throw new NotSupportedException();
public Task<bool> CanOpenAsync() => Task.FromResult(true);
public void Destroy() { }
public void Unload() { }
public override Task<bool> CanHandlePath(string path) => Task.FromResult(path.StartsWith("smb://") || path.StartsWith(@"\\"));
public async Task SaveServers()
{
try
{
await _persistenceService.SaveServers(_rootContainers.OfType<SmbServer>());
await _persistenceService.SaveServers(RootContainers?.OfType<SmbServer>() ?? Enumerable.Empty<SmbServer>());
}
catch (Exception e)
{
@@ -163,41 +88,10 @@ namespace FileTime.Providers.Smb
}
}
private async Task Init()
protected override async Task Init()
{
while (true)
{
lock (_initializationGuard)
{
if (!_initializing)
{
_initializing = true;
break;
}
}
await Task.Delay(1);
}
try
{
if (_initialized) return;
if (_items.Count > 0) return;
_initialized = true;
var servers = await _persistenceService.LoadServers();
foreach (var server in servers)
{
var smbServer = new SmbServer(server.Path, this, _inputInterface, server.UserName, server.Password);
_rootContainers.Add(smbServer);
}
_items = _rootContainers.OrderBy(c => c.Name).ToList().AsReadOnly();
}
finally
{
lock (_initializationGuard)
{
_initializing = false;
}
}
SetRootContainers(servers.Select(s => new SmbServer(s.Path, this, _inputInterface, s.UserName, s.Password)));
}
public static string GetNativePathSeparator() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "\\" : "/";