ContentProvider more async
This commit is contained in:
@@ -82,8 +82,8 @@ public class ContainerSizeSizeScanProvider : ContentProviderBase, IContainerSize
|
|||||||
itemInitializationSettings
|
itemInitializationSettings
|
||||||
);
|
);
|
||||||
|
|
||||||
public override NativePath GetNativePath(FullName fullName)
|
public override ValueTask<NativePath> GetNativePathAsync(FullName fullName)
|
||||||
=> new(fullName.Path);
|
=> ValueTask.FromResult(new NativePath(fullName.Path));
|
||||||
|
|
||||||
public override FullName GetFullName(NativePath nativePath)
|
public override FullName GetFullName(NativePath nativePath)
|
||||||
=> new(nativePath.Path);
|
=> new(nativePath.Path);
|
||||||
@@ -95,8 +95,8 @@ public class ContainerSizeSizeScanProvider : ContentProviderBase, IContainerSize
|
|||||||
//TODO read from original source
|
//TODO read from original source
|
||||||
=> Task.FromResult((byte[]?) null);
|
=> Task.FromResult((byte[]?) null);
|
||||||
|
|
||||||
public override bool CanHandlePath(NativePath path)
|
public override Task<bool> CanHandlePathAsync(NativePath path)
|
||||||
=> path.Path.StartsWith(ContentProviderName);
|
=> Task.FromResult(path.Path.StartsWith(ContentProviderName));
|
||||||
|
|
||||||
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => null;
|
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => null;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ using FileTime.Core.Timeline;
|
|||||||
using FileTime.Providers.Remote;
|
using FileTime.Providers.Remote;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server.Common;
|
||||||
using FileTime.Server.Common.Connections.SignalR;
|
using FileTime.Server.Common.Connections.SignalR;
|
||||||
using InitableService;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||||
@@ -28,7 +27,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||||
private readonly IContainerSizeScanProvider _containerSizeScanProvider;
|
private readonly IContainerSizeScanProvider _containerSizeScanProvider;
|
||||||
private readonly IProgramsService _programsService;
|
private readonly IProgramsService _programsService;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IContentProviderRegistry _contentProviderRegistry;
|
||||||
private readonly ILogger<ToolUserCommandHandlerService> _logger;
|
private readonly ILogger<ToolUserCommandHandlerService> _logger;
|
||||||
private IDeclarativeProperty<IContainer?>? _currentLocation;
|
private IDeclarativeProperty<IContainer?>? _currentLocation;
|
||||||
private IDeclarativeProperty<IItemViewModel?>? _currentSelectedItem;
|
private IDeclarativeProperty<IItemViewModel?>? _currentSelectedItem;
|
||||||
@@ -45,7 +44,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
IContentAccessorFactory contentAccessorFactory,
|
IContentAccessorFactory contentAccessorFactory,
|
||||||
IContainerSizeScanProvider containerSizeScanProvider,
|
IContainerSizeScanProvider containerSizeScanProvider,
|
||||||
IProgramsService programsService,
|
IProgramsService programsService,
|
||||||
IServiceProvider serviceProvider,
|
IContentProviderRegistry contentProviderRegistry,
|
||||||
ILogger<ToolUserCommandHandlerService> logger) : base(appState)
|
ILogger<ToolUserCommandHandlerService> logger) : base(appState)
|
||||||
{
|
{
|
||||||
_systemClipboardService = systemClipboardService;
|
_systemClipboardService = systemClipboardService;
|
||||||
@@ -57,7 +56,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
_contentAccessorFactory = contentAccessorFactory;
|
_contentAccessorFactory = contentAccessorFactory;
|
||||||
_containerSizeScanProvider = containerSizeScanProvider;
|
_containerSizeScanProvider = containerSizeScanProvider;
|
||||||
_programsService = programsService;
|
_programsService = programsService;
|
||||||
_serviceProvider = serviceProvider;
|
_contentProviderRegistry = contentProviderRegistry;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
SaveCurrentLocation(l => _currentLocation = l);
|
SaveCurrentLocation(l => _currentLocation = l);
|
||||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||||
@@ -81,7 +80,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
var containerNameInput = new TextInputElement("Path");
|
var containerNameInput = new TextInputElement("Path");
|
||||||
var providerName = new TextInputElement("Provider name")
|
var providerName = new TextInputElement("Provider name")
|
||||||
{
|
{
|
||||||
Value = "remote_" + Guid.NewGuid().ToString("N")
|
Value = "remote_" + Guid.NewGuid().ToString("N")[..8]
|
||||||
};
|
};
|
||||||
var inputs = new IInputElement[] {containerNameInput, providerName};
|
var inputs = new IInputElement[] {containerNameInput, providerName};
|
||||||
var result = await _userCommunicationService.ReadInputs(inputs);
|
var result = await _userCommunicationService.ReadInputs(inputs);
|
||||||
@@ -113,6 +112,12 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
connection,
|
connection,
|
||||||
"local",
|
"local",
|
||||||
providerName.Value);
|
providerName.Value);
|
||||||
|
|
||||||
|
_contentProviderRegistry.AddContentProvider(remoteContentProvider);
|
||||||
|
|
||||||
|
|
||||||
|
await _userCommandHandlerService.HandleCommandAsync(
|
||||||
|
new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, remoteContentProvider)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Edit()
|
private Task Edit()
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ public class SearchContentProvider : ContentProviderBase, ISearchContentProvider
|
|||||||
.First(searchTask => searchTask.SearchContainer.NativePath == nativePath).SearchContainer);
|
.First(searchTask => searchTask.SearchContainer.NativePath == nativePath).SearchContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NativePath GetNativePath(FullName fullName) => new(fullName.Path);
|
public override ValueTask<NativePath> GetNativePathAsync(FullName fullName)
|
||||||
|
=> ValueTask.FromResult(new NativePath(fullName.Path));
|
||||||
|
|
||||||
public override FullName GetFullName(NativePath nativePath) => new(nativePath.Path);
|
public override FullName GetFullName(NativePath nativePath) => new(nativePath.Path);
|
||||||
|
|
||||||
public override Task<byte[]?> GetContentAsync(
|
public override Task<byte[]?> GetContentAsync(
|
||||||
@@ -76,7 +78,7 @@ public class SearchContentProvider : ContentProviderBase, ISearchContentProvider
|
|||||||
)
|
)
|
||||||
=> Task.FromResult(null as byte[]);
|
=> Task.FromResult(null as byte[]);
|
||||||
|
|
||||||
public override bool CanHandlePath(NativePath path) => path.Path.StartsWith(ContentProviderName);
|
public override Task<bool> CanHandlePathAsync(NativePath path) => Task.FromResult(path.Path.StartsWith(ContentProviderName));
|
||||||
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => null;
|
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => null;
|
||||||
|
|
||||||
public async Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn)
|
public async Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn)
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ using FileTime.App.Core.Services;
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.App.Core.ViewModels.Timeline;
|
using FileTime.App.Core.ViewModels.Timeline;
|
||||||
using FileTime.App.FrequencyNavigation.ViewModels;
|
using FileTime.App.FrequencyNavigation.ViewModels;
|
||||||
using FileTime.ConsoleUI.App.Preview;
|
|
||||||
using FileTime.ConsoleUI.App.Services;
|
using FileTime.ConsoleUI.App.Services;
|
||||||
using FileTime.Core.Interactions;
|
using FileTime.Core.Interactions;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using PropertyChanged.SourceGenerator;
|
|
||||||
|
|
||||||
namespace FileTime.ConsoleUI.App;
|
namespace FileTime.ConsoleUI.App;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using FileTime.ConsoleUI.App;
|
using FileTime.ConsoleUI.App.Styling;
|
||||||
using FileTime.ConsoleUI.App.Styling;
|
|
||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
using TerminalUI.ConsoleDrivers;
|
using TerminalUI.ConsoleDrivers;
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ namespace FileTime.Core.Command;
|
|||||||
|
|
||||||
public interface ICommandHandler
|
public interface ICommandHandler
|
||||||
{
|
{
|
||||||
bool CanHandle(ICommand command);
|
Task<bool> CanHandleAsync(ICommand command);
|
||||||
Task ExecuteAsync(ICommand command);
|
Task ExecuteAsync(ICommand command);
|
||||||
}
|
}
|
||||||
@@ -22,11 +22,11 @@ public interface IContentProvider : IContainer, IOnContainerEnter
|
|||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
ItemInitializationSettings itemInitializationSettings = default);
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
|
|
||||||
NativePath GetNativePath(FullName fullName);
|
ValueTask<NativePath> GetNativePathAsync(FullName fullName);
|
||||||
FullName GetFullName(NativePath nativePath);
|
FullName GetFullName(NativePath nativePath);
|
||||||
|
|
||||||
Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default);
|
Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default);
|
||||||
bool CanHandlePath(NativePath path);
|
Task<bool> CanHandlePathAsync(NativePath path);
|
||||||
bool CanHandlePath(FullName path);
|
Task<bool> CanHandlePathAsync(FullName path);
|
||||||
VolumeSizeInfo? GetVolumeSizeInfo(FullName path);
|
VolumeSizeInfo? GetVolumeSizeInfo(FullName path);
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,6 @@ public interface ITimelessContentProvider
|
|||||||
ItemInitializationSettings itemInitializationSettings = default);
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
|
|
||||||
Task<IItem?> GetItemByNativePathAsync(NativePath nativePath, PointInTime? pointInTime = null);
|
Task<IItem?> GetItemByNativePathAsync(NativePath nativePath, PointInTime? pointInTime = null);
|
||||||
FullName? GetFullNameByNativePath(NativePath nativePath);
|
ValueTask<FullName?> GetFullNameByNativePathAsync(NativePath nativePath);
|
||||||
NativePath? GetNativePathByFullName(FullName fullName);
|
ValueTask<NativePath?> GetNativePathByFullNameAsync(FullName fullName);
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,10 @@ public class CommandRunner : ICommandRunner
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var commandHandler = _commandHandlers.Find(c => c.CanHandle(command));
|
var commandHandler = await _commandHandlers
|
||||||
|
.ToAsyncEnumerable()
|
||||||
|
.FirstOrDefaultAwaitAsync(async c => await c.CanHandleAsync(command));
|
||||||
|
|
||||||
if (commandHandler != null)
|
if (commandHandler != null)
|
||||||
{
|
{
|
||||||
await commandHandler.ExecuteAsync(command);
|
await commandHandler.ExecuteAsync(command);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
||||||
|
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -11,4 +11,8 @@
|
|||||||
<ProjectReference Include="..\FileTime.Core.Command\FileTime.Core.Command.csproj" />
|
<ProjectReference Include="..\FileTime.Core.Command\FileTime.Core.Command.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -18,25 +18,30 @@ public class StreamCopyCommandHandler : ICommandHandler
|
|||||||
_contentAccessorFactory = contentAccessorFactory;
|
_contentAccessorFactory = contentAccessorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanHandle(ICommand command)
|
public async Task<bool> CanHandleAsync(ICommand command)
|
||||||
{
|
{
|
||||||
if (command is not CopyCommand copyCommand) return false;
|
if (command is not CopyCommand copyCommand) return false;
|
||||||
|
|
||||||
var targetSupportsContentStream =
|
var targetSupportsContentStream =
|
||||||
_contentProviderRegistry
|
(await _contentProviderRegistry
|
||||||
.ContentProviders
|
.ContentProviders
|
||||||
.FirstOrDefault(p => p.CanHandlePath(copyCommand.Target!))
|
.ToAsyncEnumerable()
|
||||||
?.SupportsContentStreams ?? false;
|
.FirstOrDefaultAwaitAsync(async p => await p.CanHandlePathAsync(copyCommand.Target))
|
||||||
|
)?.SupportsContentStreams ?? false;
|
||||||
|
|
||||||
var allSourcesSupportsContentStream =
|
var allSourcesSupportsContentStream =
|
||||||
copyCommand
|
(await copyCommand
|
||||||
.Sources
|
.Sources
|
||||||
.Select(s =>
|
.ToAsyncEnumerable()
|
||||||
|
.SelectAwait(s =>
|
||||||
_contentProviderRegistry
|
_contentProviderRegistry
|
||||||
.ContentProviders
|
.ContentProviders
|
||||||
.FirstOrDefault(p => p.CanHandlePath(s))
|
.ToAsyncEnumerable()
|
||||||
|
.FirstOrDefaultAwaitAsync(async p => await p.CanHandlePathAsync(s))
|
||||||
)
|
)
|
||||||
.All(p => p?.SupportsContentStreams ?? false);
|
.ToListAsync()
|
||||||
|
)
|
||||||
|
.All(p => p?.SupportsContentStreams ?? false);
|
||||||
|
|
||||||
return targetSupportsContentStream && allSourcesSupportsContentStream;
|
return targetSupportsContentStream && allSourcesSupportsContentStream;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public abstract class ContentProviderBase : IContentProvider
|
|||||||
bool forceResolve = false,
|
bool forceResolve = false,
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
ItemInitializationSettings itemInitializationSettings = default)
|
ItemInitializationSettings itemInitializationSettings = default)
|
||||||
=> await GetItemByNativePathAsync(GetNativePath(fullName), pointInTime, forceResolve, forceResolvePathType,
|
=> await GetItemByNativePathAsync(await GetNativePathAsync(fullName), pointInTime, forceResolve, forceResolvePathType,
|
||||||
itemInitializationSettings);
|
itemInitializationSettings);
|
||||||
|
|
||||||
public abstract Task<IItem> GetItemByNativePathAsync(NativePath nativePath,
|
public abstract Task<IItem> GetItemByNativePathAsync(NativePath nativePath,
|
||||||
@@ -81,15 +81,18 @@ public abstract class ContentProviderBase : IContentProvider
|
|||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
ItemInitializationSettings itemInitializationSettings = default);
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
|
|
||||||
public abstract NativePath GetNativePath(FullName fullName);
|
public abstract ValueTask<NativePath> GetNativePathAsync(FullName fullName);
|
||||||
public abstract FullName GetFullName(NativePath nativePath);
|
public abstract FullName GetFullName(NativePath nativePath);
|
||||||
|
|
||||||
public abstract Task<byte[]?> GetContentAsync(IElement element,
|
public abstract Task<byte[]?> GetContentAsync(IElement element,
|
||||||
int? maxLength = null,
|
int? maxLength = null,
|
||||||
CancellationToken cancellationToken = default);
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
public abstract bool CanHandlePath(NativePath path);
|
public abstract Task<bool> CanHandlePathAsync(NativePath path);
|
||||||
public bool CanHandlePath(FullName path) => CanHandlePath(GetNativePath(path));
|
public async Task<bool> CanHandlePathAsync(FullName path)
|
||||||
|
=> path.Path.TrimEnd(Constants.SeparatorChar) == Name
|
||||||
|
|| await CanHandlePathAsync(await GetNativePathAsync(path));
|
||||||
|
|
||||||
public abstract VolumeSizeInfo? GetVolumeSizeInfo(FullName path);
|
public abstract VolumeSizeInfo? GetVolumeSizeInfo(FullName path);
|
||||||
|
|
||||||
public IItem WithParent(AbsolutePath parent) => this;
|
public IItem WithParent(AbsolutePath parent) => this;
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public class RootContentProvider : IRootContentProvider
|
|||||||
pointInTime
|
pointInTime
|
||||||
) ?? throw new FileNotFoundException();
|
) ?? throw new FileNotFoundException();
|
||||||
|
|
||||||
public NativePath GetNativePath(FullName fullName) => throw new NotImplementedException();
|
public ValueTask<NativePath> GetNativePathAsync(FullName fullName) => throw new NotImplementedException();
|
||||||
|
|
||||||
public FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
public FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
||||||
|
|
||||||
@@ -82,9 +82,9 @@ public class RootContentProvider : IRootContentProvider
|
|||||||
int? maxLength = null,
|
int? maxLength = null,
|
||||||
CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||||
|
|
||||||
public bool CanHandlePath(NativePath path) => throw new NotImplementedException();
|
public Task<bool> CanHandlePathAsync(NativePath path) => throw new NotImplementedException();
|
||||||
|
|
||||||
public bool CanHandlePath(FullName path) => throw new NotImplementedException();
|
public Task<bool> CanHandlePathAsync(FullName path) => throw new NotImplementedException();
|
||||||
public VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => null;
|
public VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => null;
|
||||||
|
|
||||||
public IItem WithParent(AbsolutePath parent) => this;
|
public IItem WithParent(AbsolutePath parent) => this;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class TimelessContentProvider : ITimelessContentProvider
|
|||||||
{
|
{
|
||||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||||
{
|
{
|
||||||
if (!contentProvider.CanHandlePath(nativePath)) continue;
|
if (!await contentProvider.CanHandlePathAsync(nativePath)) continue;
|
||||||
|
|
||||||
return await contentProvider.GetItemByNativePathAsync(nativePath, pointInTime ?? PointInTime.Present);
|
return await contentProvider.GetItemByNativePathAsync(nativePath, pointInTime ?? PointInTime.Present);
|
||||||
}
|
}
|
||||||
@@ -53,11 +53,11 @@ public class TimelessContentProvider : ITimelessContentProvider
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FullName? GetFullNameByNativePath(NativePath nativePath)
|
public async ValueTask<FullName?> GetFullNameByNativePathAsync(NativePath nativePath)
|
||||||
{
|
{
|
||||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||||
{
|
{
|
||||||
if (!contentProvider.CanHandlePath(nativePath)) continue;
|
if (!await contentProvider.CanHandlePathAsync(nativePath)) continue;
|
||||||
|
|
||||||
return contentProvider.GetFullName(nativePath);
|
return contentProvider.GetFullName(nativePath);
|
||||||
}
|
}
|
||||||
@@ -65,13 +65,13 @@ public class TimelessContentProvider : ITimelessContentProvider
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativePath? GetNativePathByFullName(FullName fullName)
|
public async ValueTask<NativePath?> GetNativePathByFullNameAsync(FullName fullName)
|
||||||
{
|
{
|
||||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||||
{
|
{
|
||||||
if (!contentProvider.CanHandlePath(fullName)) continue;
|
if (!await contentProvider.CanHandlePathAsync(fullName)) continue;
|
||||||
|
|
||||||
return contentProvider.GetNativePath(fullName);
|
return await contentProvider.GetNativePathAsync(fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class SystemClipboardService : ISystemClipboardService
|
|||||||
if (obj is IEnumerable<IStorageItem> storageItems)
|
if (obj is IEnumerable<IStorageItem> storageItems)
|
||||||
{
|
{
|
||||||
return storageItems
|
return storageItems
|
||||||
.Select(i => _timelessContentProvider.GetFullNameByNativePath(new NativePath(WebUtility.UrlDecode(i.Path.AbsolutePath))))
|
.Select(i => _timelessContentProvider.GetFullNameByNativePathAsync(new NativePath(WebUtility.UrlDecode(i.Path.AbsolutePath))))
|
||||||
.Where(i => i != null)
|
.Where(i => i != null)
|
||||||
.OfType<FullName>();
|
.OfType<FullName>();
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ public class SystemClipboardService : ISystemClipboardService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fileNativePaths = files
|
var fileNativePaths = files
|
||||||
.Select(i => _timelessContentProvider.GetNativePathByFullName(i))
|
.Select(i => _timelessContentProvider.GetNativePathByFullNameAsync(i))
|
||||||
.Where(i => i != null)
|
.Where(i => i != null)
|
||||||
.OfType<NativePath>();
|
.OfType<NativePath>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection.Metadata;
|
using PropertyChanged.SourceGenerator;
|
||||||
using PropertyChanged.SourceGenerator;
|
|
||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
using TerminalUI.Models;
|
using TerminalUI.Models;
|
||||||
using TerminalUI.Traits;
|
using TerminalUI.Traits;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
using FileTime.Core.ContentAccess;
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.Providers.Local;
|
namespace FileTime.Providers.Local;
|
||||||
|
|
||||||
public interface ILocalContentProvider : IContentProvider
|
public interface ILocalContentProvider : IContentProvider
|
||||||
{
|
{
|
||||||
|
NativePath GetNativePath(FullName fullName);
|
||||||
}
|
}
|
||||||
@@ -54,12 +54,13 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
});*/
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanHandlePath(NativePath path)
|
public override async Task<bool> CanHandlePathAsync(NativePath path)
|
||||||
{
|
{
|
||||||
var rootDrive = Items
|
var rootDrive = await Items
|
||||||
.FirstOrDefault(r =>
|
.ToAsyncEnumerable()
|
||||||
|
.FirstOrDefaultAwaitAsync(async r =>
|
||||||
path.Path.StartsWith(
|
path.Path.StartsWith(
|
||||||
GetNativePath(r.Path).Path,
|
(await GetNativePathAsync(r.Path)).Path,
|
||||||
_isCaseInsensitive
|
_isCaseInsensitive
|
||||||
? StringComparison.InvariantCultureIgnoreCase
|
? StringComparison.InvariantCultureIgnoreCase
|
||||||
: StringComparison.InvariantCulture
|
: StringComparison.InvariantCulture
|
||||||
@@ -74,7 +75,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
var rootDriveInfos = _rootDriveInfos.Value;
|
var rootDriveInfos = _rootDriveInfos.Value;
|
||||||
var rootDriveInfo = rootDriveInfos.FirstOrDefault(d => path.Path.StartsWith(d.Path.Path));
|
var rootDriveInfo = rootDriveInfos.FirstOrDefault(d => path.Path.StartsWith(d.Path.Path));
|
||||||
|
|
||||||
if(rootDriveInfo is null) return null;
|
if (rootDriveInfo is null) return null;
|
||||||
|
|
||||||
return new VolumeSizeInfo(rootDriveInfo.Size, rootDriveInfo.Free);
|
return new VolumeSizeInfo(rootDriveInfo.Size, rootDriveInfo.Free);
|
||||||
}
|
}
|
||||||
@@ -391,7 +392,10 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
nativePath.TrimStart(Constants.SeparatorChar).Split(Path.DirectorySeparatorChar)))
|
nativePath.TrimStart(Constants.SeparatorChar).Split(Path.DirectorySeparatorChar)))
|
||||||
.TrimEnd(Constants.SeparatorChar))!;
|
.TrimEnd(Constants.SeparatorChar))!;
|
||||||
|
|
||||||
public override NativePath GetNativePath(FullName fullName)
|
public override ValueTask<NativePath> GetNativePathAsync(FullName fullName)
|
||||||
|
=> ValueTask.FromResult(GetNativePath(fullName));
|
||||||
|
|
||||||
|
public NativePath GetNativePath(FullName fullName)
|
||||||
{
|
{
|
||||||
var path = string.Join(Path.DirectorySeparatorChar, fullName.Path.Split(Constants.SeparatorChar).Skip(1));
|
var path = string.Join(Path.DirectorySeparatorChar, fullName.Path.Split(Constants.SeparatorChar).Skip(1));
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !path.StartsWith("/")) path = "/" + path;
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !path.StartsWith("/")) path = "/" + path;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class LocalItemCreator : ItemCreatorBase<ILocalContentProvider>
|
|||||||
public override async Task CreateContainerAsync(ILocalContentProvider contentProvider, FullName fullName)
|
public override async Task CreateContainerAsync(ILocalContentProvider contentProvider, FullName fullName)
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Start creating container {FullName}", fullName);
|
_logger.LogTrace("Start creating container {FullName}", fullName);
|
||||||
var path = contentProvider.GetNativePath(fullName).Path;
|
var path = (await contentProvider.GetNativePathAsync(fullName)).Path;
|
||||||
if (Directory.Exists(path))
|
if (Directory.Exists(path))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Container with path {Path} already exists", path);
|
_logger.LogTrace("Container with path {Path} already exists", path);
|
||||||
@@ -54,7 +54,7 @@ public class LocalItemCreator : ItemCreatorBase<ILocalContentProvider>
|
|||||||
public override async Task CreateElementAsync(ILocalContentProvider contentProvider, FullName fullName)
|
public override async Task CreateElementAsync(ILocalContentProvider contentProvider, FullName fullName)
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Start creating element {FullName}", fullName);
|
_logger.LogTrace("Start creating element {FullName}", fullName);
|
||||||
var path = contentProvider.GetNativePath(fullName).Path;
|
var path = (await contentProvider.GetNativePathAsync(fullName)).Path;
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Element with path {Path} already exists", path);
|
_logger.LogTrace("Element with path {Path} already exists", path);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class LocalItemDeleter : IItemDeleter<ILocalContentProvider>
|
|||||||
public async Task DeleteAsync(ILocalContentProvider contentProvider, FullName fullName)
|
public async Task DeleteAsync(ILocalContentProvider contentProvider, FullName fullName)
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Start deleting item {FullName}", fullName);
|
_logger.LogTrace("Start deleting item {FullName}", fullName);
|
||||||
var nativePath = contentProvider.GetNativePath(fullName).Path;
|
var nativePath = (await contentProvider.GetNativePathAsync(fullName)).Path;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ public class LocalItemMover : IItemMover<ILocalContentProvider>
|
|||||||
_logger.LogTrace("Start renaming item {FullName}", fullName);
|
_logger.LogTrace("Start renaming item {FullName}", fullName);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var source = contentProvider.GetNativePath(fullName);
|
var source = await contentProvider.GetNativePathAsync(fullName);
|
||||||
var destination = contentProvider.GetNativePath(newPath);
|
var destination = await contentProvider.GetNativePathAsync(newPath);
|
||||||
|
|
||||||
if (File.Exists(source.Path))
|
if (File.Exists(source.Path))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Providers.Remote;
|
using FileTime.Providers.Remote;
|
||||||
using FileTime.Server.Common;
|
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.Providers.LocalAdmin;
|
namespace FileTime.Providers.LocalAdmin;
|
||||||
|
|||||||
@@ -21,18 +21,51 @@ public sealed class RemoteContentProvider : ContentProviderBase, IRemoteContentP
|
|||||||
RemoteProviderName = remoteName;
|
RemoteProviderName = remoteName;
|
||||||
_remoteConnectionProvider = remoteConnectionProvider;
|
_remoteConnectionProvider = remoteConnectionProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IRemoteConnection> GetRemoteConnectionAsync()
|
public async Task<IRemoteConnection> GetRemoteConnectionAsync()
|
||||||
=> await _remoteConnectionProvider();
|
=> await _remoteConnectionProvider();
|
||||||
|
|
||||||
//TODO implement
|
//TODO implement
|
||||||
public override Task<IItem> GetItemByNativePathAsync(NativePath nativePath, PointInTime pointInTime, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, ItemInitializationSettings itemInitializationSettings = default) => throw new NotImplementedException();
|
public override Task<IItem> GetItemByNativePathAsync(
|
||||||
|
NativePath nativePath,
|
||||||
|
PointInTime pointInTime,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default) =>
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
public override NativePath GetNativePath(FullName fullName) => throw new NotImplementedException();
|
//TODO: make it async
|
||||||
|
public override async ValueTask<NativePath> GetNativePathAsync(FullName fullName)
|
||||||
|
{
|
||||||
|
var remoteFullname = new FullName(ConvertLocalFullNameToRemote(fullName));
|
||||||
|
|
||||||
|
var connection = await GetRemoteConnectionAsync();
|
||||||
|
var remoteNativePath = await connection.GetNativePathAsync(remoteFullname);
|
||||||
|
return new NativePath(remoteNativePath!.Path);
|
||||||
|
}
|
||||||
|
|
||||||
public override FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
public override FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
public override Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override bool CanHandlePath(NativePath path) => throw new NotImplementedException();
|
public override Task<bool> CanHandlePathAsync(NativePath path) => throw new NotImplementedException();
|
||||||
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => throw new NotImplementedException();
|
public override VolumeSizeInfo? GetVolumeSizeInfo(FullName path) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
private string ConvertLocalFullNameToRemote(FullName fullName)
|
||||||
|
{
|
||||||
|
var remotePath =
|
||||||
|
RemoteProviderName
|
||||||
|
+ Constants.SeparatorChar
|
||||||
|
+ fullName.Path[Name.Length..];
|
||||||
|
return remotePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FullName ConvertRemoteFullnameToLocal(string remotePath)
|
||||||
|
{
|
||||||
|
var localPath =
|
||||||
|
Name
|
||||||
|
+ Constants.SeparatorChar
|
||||||
|
+ remotePath[RemoteProviderName.Length..];
|
||||||
|
return new FullName(localPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using FileTime.Core.ContentAccess;
|
using FileTime.Core.ContentAccess;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Server.Common;
|
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.Providers.Remote;
|
namespace FileTime.Providers.Remote;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using FileTime.Core.ContentAccess;
|
using FileTime.Core.ContentAccess;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Server.Common;
|
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.Providers.Remote;
|
namespace FileTime.Providers.Remote;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using FileTime.Providers.LocalAdmin;
|
using FileTime.Providers.LocalAdmin;
|
||||||
using FileTime.Providers.Remote;
|
using FileTime.Providers.Remote;
|
||||||
using FileTime.Server.Common;
|
|
||||||
|
|
||||||
namespace FileTime.Server.App;
|
namespace FileTime.Server.App;
|
||||||
|
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ public interface IRemoteConnection
|
|||||||
Task WriteBytesAsync(string transactionId, byte[] data, int? index, CancellationToken cancellationToken = default);
|
Task WriteBytesAsync(string transactionId, byte[] data, int? index, CancellationToken cancellationToken = default);
|
||||||
Task FlushWriterAsync(string transactionId, CancellationToken cancellationToken = default);
|
Task FlushWriterAsync(string transactionId, CancellationToken cancellationToken = default);
|
||||||
Task CloseWriterAsync(string transactionId);
|
Task CloseWriterAsync(string transactionId);
|
||||||
|
Task<NativePath?> GetNativePathAsync(FullName fullName);
|
||||||
}
|
}
|
||||||
@@ -15,4 +15,5 @@ public interface ISignalRHub
|
|||||||
//TODO: CancellationToken https://github.com/nenoNaninu/TypedSignalR.Client/issues/120
|
//TODO: CancellationToken https://github.com/nenoNaninu/TypedSignalR.Client/issues/120
|
||||||
Task WriteBytesAsync(string transactionId, string data, int index);
|
Task WriteBytesAsync(string transactionId, string data, int index);
|
||||||
Task CloseWriterAsync(string transactionId);
|
Task CloseWriterAsync(string transactionId);
|
||||||
|
Task<string?> GetNativePathAsync(string fullNamePath);
|
||||||
}
|
}
|
||||||
@@ -77,4 +77,10 @@ public class SignalRConnection : IRemoteConnection, IAsyncInitable<string>
|
|||||||
|
|
||||||
public async Task CloseWriterAsync(string transactionId)
|
public async Task CloseWriterAsync(string transactionId)
|
||||||
=> await _client.CloseWriterAsync(transactionId);
|
=> await _client.CloseWriterAsync(transactionId);
|
||||||
|
|
||||||
|
public async Task<NativePath?> GetNativePathAsync(FullName fullName)
|
||||||
|
{
|
||||||
|
var path = await _client.GetNativePathAsync(fullName.Path);
|
||||||
|
return path is null ? null : new NativePath(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,17 +14,20 @@ public class ConnectionHub : Hub<ISignalRClient>, ISignalRHub
|
|||||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||||
private readonly IApplicationStopper _applicationStopper;
|
private readonly IApplicationStopper _applicationStopper;
|
||||||
private readonly IContentAccessManager _contentAccessManager;
|
private readonly IContentAccessManager _contentAccessManager;
|
||||||
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
|
|
||||||
public ConnectionHub(
|
public ConnectionHub(
|
||||||
IContentProviderRegistry contentProviderRegistry,
|
IContentProviderRegistry contentProviderRegistry,
|
||||||
IContentAccessorFactory contentAccessorFactory,
|
IContentAccessorFactory contentAccessorFactory,
|
||||||
IApplicationStopper applicationStopper,
|
IApplicationStopper applicationStopper,
|
||||||
IContentAccessManager contentAccessManager)
|
IContentAccessManager contentAccessManager,
|
||||||
|
ITimelessContentProvider timelessContentProvider)
|
||||||
{
|
{
|
||||||
_contentProviderRegistry = contentProviderRegistry;
|
_contentProviderRegistry = contentProviderRegistry;
|
||||||
_contentAccessorFactory = contentAccessorFactory;
|
_contentAccessorFactory = contentAccessorFactory;
|
||||||
_applicationStopper = applicationStopper;
|
_applicationStopper = applicationStopper;
|
||||||
_contentAccessManager = contentAccessManager;
|
_contentAccessManager = contentAccessManager;
|
||||||
|
_timelessContentProvider = timelessContentProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Exit()
|
public Task Exit()
|
||||||
@@ -86,4 +89,7 @@ public class ConnectionHub : Hub<ISignalRClient>, ISignalRHub
|
|||||||
_contentAccessManager.RemoveContentWriter(transactionId);
|
_contentAccessManager.RemoveContentWriter(transactionId);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<string?> GetNativePathAsync(string fullNamePath)
|
||||||
|
=> (await _timelessContentProvider.GetNativePathByFullNameAsync(new FullName(fullNamePath)))?.Path;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user