RemoteContentProvider get items WIP
This commit is contained in:
@@ -28,6 +28,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
private readonly IContainerSizeScanProvider _containerSizeScanProvider;
|
private readonly IContainerSizeScanProvider _containerSizeScanProvider;
|
||||||
private readonly IProgramsService _programsService;
|
private readonly IProgramsService _programsService;
|
||||||
private readonly IContentProviderRegistry _contentProviderRegistry;
|
private readonly IContentProviderRegistry _contentProviderRegistry;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
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,6 +46,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
IContainerSizeScanProvider containerSizeScanProvider,
|
IContainerSizeScanProvider containerSizeScanProvider,
|
||||||
IProgramsService programsService,
|
IProgramsService programsService,
|
||||||
IContentProviderRegistry contentProviderRegistry,
|
IContentProviderRegistry contentProviderRegistry,
|
||||||
|
IServiceProvider serviceProvider,
|
||||||
ILogger<ToolUserCommandHandlerService> logger) : base(appState)
|
ILogger<ToolUserCommandHandlerService> logger) : base(appState)
|
||||||
{
|
{
|
||||||
_systemClipboardService = systemClipboardService;
|
_systemClipboardService = systemClipboardService;
|
||||||
@@ -57,6 +59,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
_containerSizeScanProvider = containerSizeScanProvider;
|
_containerSizeScanProvider = containerSizeScanProvider;
|
||||||
_programsService = programsService;
|
_programsService = programsService;
|
||||||
_contentProviderRegistry = contentProviderRegistry;
|
_contentProviderRegistry = contentProviderRegistry;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
SaveCurrentLocation(l => _currentLocation = l);
|
SaveCurrentLocation(l => _currentLocation = l);
|
||||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||||
@@ -92,7 +95,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
Func<Task<IRemoteConnection>>? connection = null;
|
Func<Task<IRemoteConnection>>? connection = null;
|
||||||
if (path.StartsWith("http"))
|
if (path.StartsWith("http"))
|
||||||
{
|
{
|
||||||
connection = async () => await SignalRConnection.GetOrCreateForAsync(path);
|
connection = async () => await SignalRConnection.GetOrCreateForAsync(path, providerName.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection is null)
|
if (connection is null)
|
||||||
@@ -109,15 +112,17 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
|
|
||||||
var remoteContentProvider = new RemoteContentProvider(
|
var remoteContentProvider = new RemoteContentProvider(
|
||||||
_timelessContentProvider,
|
_timelessContentProvider,
|
||||||
|
_serviceProvider,
|
||||||
connection,
|
connection,
|
||||||
"local",
|
"local",
|
||||||
providerName.Value);
|
providerName.Value);
|
||||||
|
|
||||||
_contentProviderRegistry.AddContentProvider(remoteContentProvider);
|
_contentProviderRegistry.AddContentProvider(remoteContentProvider);
|
||||||
|
|
||||||
|
|
||||||
await _userCommandHandlerService.HandleCommandAsync(
|
await _userCommandHandlerService.HandleCommandAsync(
|
||||||
new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, remoteContentProvider)));
|
new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, remoteContentProvider)));
|
||||||
|
|
||||||
|
await remoteContentProvider.InitializeChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Edit()
|
private Task Edit()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace FileTime.App.Core;
|
|||||||
|
|
||||||
public static class Startup
|
public static class Startup
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddCoreAppServices(this IServiceCollection serviceCollection, IConfigurationRoot configuration)
|
public static IServiceCollection AddAppCoreDependencies(this IServiceCollection serviceCollection, IConfigurationRoot configuration)
|
||||||
{
|
{
|
||||||
serviceCollection.TryAddTransient<ITabViewModel, TabViewModel>();
|
serviceCollection.TryAddTransient<ITabViewModel, TabViewModel>();
|
||||||
serviceCollection.TryAddTransient<IContainerViewModel, ContainerViewModel>();
|
serviceCollection.TryAddTransient<IContainerViewModel, ContainerViewModel>();
|
||||||
|
|||||||
@@ -2,14 +2,7 @@ using FileTime.App.Core;
|
|||||||
using FileTime.App.Core.Models;
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Services;
|
||||||
using FileTime.App.Core.Services.Persistence;
|
using FileTime.App.Core.Services.Persistence;
|
||||||
using FileTime.Core.Command;
|
using FileTime.Core;
|
||||||
using FileTime.Core.Command.CreateContainer;
|
|
||||||
using FileTime.Core.Command.CreateElement;
|
|
||||||
using FileTime.Core.Command.Delete;
|
|
||||||
using FileTime.Core.CommandHandlers;
|
|
||||||
using FileTime.Core.ContentAccess;
|
|
||||||
using FileTime.Core.Services;
|
|
||||||
using FileTime.Core.Timeline;
|
|
||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
using FileTime.Providers.LocalAdmin;
|
using FileTime.Providers.LocalAdmin;
|
||||||
using FileTime.Providers.Remote;
|
using FileTime.Providers.Remote;
|
||||||
@@ -25,36 +18,16 @@ public static class DependencyInjection
|
|||||||
{
|
{
|
||||||
serviceCollection ??= new ServiceCollection();
|
serviceCollection ??= new ServiceCollection();
|
||||||
|
|
||||||
serviceCollection.TryAddSingleton<ICommandScheduler, CommandScheduler>();
|
|
||||||
serviceCollection.TryAddSingleton<ITimelessContentProvider, TimelessContentProvider>();
|
|
||||||
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
|
|
||||||
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
|
|
||||||
serviceCollection.TryAddSingleton<IContentProviderRegistry, ContentProviderRegistry>();
|
|
||||||
serviceCollection.TryAddSingleton<IRootContentProvider, RootContentProvider>();
|
|
||||||
//TODO: check local/remote context
|
|
||||||
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
|
|
||||||
serviceCollection.TryAddSingleton<ICommandSchedulerNotifier, LocalCommandSchedulerNotifier>();
|
|
||||||
|
|
||||||
serviceCollection.TryAddSingleton<IApplicationSettings, ApplicationSettings>();
|
serviceCollection.TryAddSingleton<IApplicationSettings, ApplicationSettings>();
|
||||||
serviceCollection.TryAddSingleton<ITabPersistenceService, TabPersistenceService>();
|
serviceCollection.TryAddSingleton<ITabPersistenceService, TabPersistenceService>();
|
||||||
serviceCollection.TryAddTransient<ITab, Tab>();
|
|
||||||
serviceCollection.TryAddSingleton<ITabEvents, TabEvents>();
|
|
||||||
serviceCollection.AddSingleton<IExitHandler, ITabPersistenceService>(sp => sp.GetRequiredService<ITabPersistenceService>());
|
serviceCollection.AddSingleton<IExitHandler, ITabPersistenceService>(sp => sp.GetRequiredService<ITabPersistenceService>());
|
||||||
serviceCollection.AddSingleton<IStartupHandler, ITabPersistenceService>(sp => sp.GetRequiredService<ITabPersistenceService>());
|
serviceCollection.AddSingleton<IStartupHandler, ITabPersistenceService>(sp => sp.GetRequiredService<ITabPersistenceService>());
|
||||||
|
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.AddCoreAppServices(configuration)
|
.AddCoreDependencies()
|
||||||
|
.AddAppCoreDependencies(configuration)
|
||||||
.AddLocalProviderServices()
|
.AddLocalProviderServices()
|
||||||
.AddLocalAdminProviderServices(configuration)
|
.AddLocalAdminProviderServices(configuration)
|
||||||
.AddRemoteProviderServices()
|
.AddRemoteProviderServices();
|
||||||
.RegisterCommands()
|
|
||||||
.AddDefaultCommandHandlers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection RegisterCommands(this IServiceCollection serviceCollection)
|
|
||||||
=> serviceCollection
|
|
||||||
.AddCommands()
|
|
||||||
.AddTransient<CreateContainerCommand>()
|
|
||||||
.AddTransient<CreateElementCommand>()
|
|
||||||
.AddTransient<DeleteCommand>();
|
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Core\FileTime.Core.CommandHandlers\FileTime.Core.CommandHandlers.csproj" />
|
<ProjectReference Include="..\..\Core\FileTime.Core.CommandHandlers\FileTime.Core.CommandHandlers.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Extensions.DependencyInjection\FileTime.Core.Extensions.DependencyInjection.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Serialization\FileTime.Core.Serialization.csproj" />
|
||||||
<ProjectReference Include="..\..\Core\FileTime.Core.Timeline\FileTime.Core.Timeline.csproj" />
|
<ProjectReference Include="..\..\Core\FileTime.Core.Timeline\FileTime.Core.Timeline.csproj" />
|
||||||
<ProjectReference Include="..\..\Providers\FileTime.Providers.LocalAdmin\FileTime.Providers.LocalAdmin.csproj" />
|
<ProjectReference Include="..\..\Providers\FileTime.Providers.LocalAdmin\FileTime.Providers.LocalAdmin.csproj" />
|
||||||
<ProjectReference Include="..\..\Providers\FileTime.Providers.Local\FileTime.Providers.Local.csproj" />
|
<ProjectReference Include="..\..\Providers\FileTime.Providers.Local\FileTime.Providers.Local.csproj" />
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using FileTime.App.Search;
|
|||||||
using FileTime.ConsoleUI.App;
|
using FileTime.ConsoleUI.App;
|
||||||
using FileTime.ConsoleUI.App.Services;
|
using FileTime.ConsoleUI.App.Services;
|
||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server;
|
||||||
using FileTime.Tools.Compression;
|
using FileTime.Tools.Compression;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<ProjectReference Include="..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
<ProjectReference Include="..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
<ProjectReference Include="..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
||||||
<ProjectReference Include="..\..\Library\TerminalUI.DependencyInjection\TerminalUI.DependencyInjection.csproj" />
|
<ProjectReference Include="..\..\Library\TerminalUI.DependencyInjection\TerminalUI.DependencyInjection.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Server\FileTime.Server.Extensions.DependencyInjection\FileTime.Server.Extensions.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\..\Tools\FileTime.Tools.Compression\FileTime.Tools.Compression.csproj" />
|
<ProjectReference Include="..\..\Tools\FileTime.Tools.Compression\FileTime.Tools.Compression.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.ConsoleUI.App\FileTime.ConsoleUI.App.csproj" />
|
<ProjectReference Include="..\FileTime.ConsoleUI.App\FileTime.ConsoleUI.App.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -25,4 +25,5 @@
|
|||||||
<ProjectReference Include="..\..\Library\InitableService\InitableService.csproj" />
|
<ProjectReference Include="..\..\Library\InitableService\InitableService.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ namespace FileTime.Core.Timeline;
|
|||||||
|
|
||||||
public class PointInTime
|
public class PointInTime
|
||||||
{
|
{
|
||||||
public static readonly PointInTime Eternal = new PointInTime();
|
public static readonly PointInTime Eternal = new();
|
||||||
public static readonly PointInTime Present = new PointInTime();
|
public static readonly PointInTime Present = new();
|
||||||
|
|
||||||
private readonly List<Difference> _differences;
|
private readonly List<Difference> _differences;
|
||||||
|
|
||||||
@@ -46,5 +46,5 @@ public class PointInTime
|
|||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PointInTime CreateEmpty() => new PointInTime();
|
public static PointInTime CreateEmpty() => new();
|
||||||
}
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using FileTime.Core.Command.Copy;
|
|
||||||
using FileTime.Core.Command.Move;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace FileTime.Core.Command;
|
|
||||||
|
|
||||||
public static class Startup
|
|
||||||
{
|
|
||||||
public static IServiceCollection AddCommands(this IServiceCollection serviceCollection) =>
|
|
||||||
serviceCollection
|
|
||||||
.AddSingleton<CopyCommandFactory>()
|
|
||||||
.AddSingleton<MoveCommandFactory>();
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using FileTime.Core.Command;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace FileTime.Core.CommandHandlers;
|
|
||||||
|
|
||||||
public static class Startup
|
|
||||||
{
|
|
||||||
public static IServiceCollection AddDefaultCommandHandlers(this IServiceCollection serviceCollection)
|
|
||||||
{
|
|
||||||
return serviceCollection
|
|
||||||
.AddSingleton<ICommandHandler, StreamCopyCommandHandler>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,6 +28,7 @@ public class ContentProviderRegistry : IContentProviderRegistry
|
|||||||
|
|
||||||
private void InitializeContentProviderListIfNeeded()
|
private void InitializeContentProviderListIfNeeded()
|
||||||
{
|
{
|
||||||
|
if (_initialized) return;
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_initialized)
|
if (!_initialized)
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>FileTime.Core</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Core.CommandHandlers\FileTime.Core.CommandHandlers.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Core.Command\FileTime.Core.Command.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Core.ContentAccess\FileTime.Core.ContentAccess.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Core.Serialization\FileTime.Core.Serialization.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Core.Services\FileTime.Core.Services.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Core.Timeline\FileTime.Core.Timeline.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
using FileTime.Core.Command;
|
||||||
|
using FileTime.Core.Command.Copy;
|
||||||
|
using FileTime.Core.Command.CreateContainer;
|
||||||
|
using FileTime.Core.Command.CreateElement;
|
||||||
|
using FileTime.Core.Command.Delete;
|
||||||
|
using FileTime.Core.Command.Move;
|
||||||
|
using FileTime.Core.CommandHandlers;
|
||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Serialization;
|
||||||
|
using FileTime.Core.Serialization.Container;
|
||||||
|
using FileTime.Core.Services;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
|
||||||
|
namespace FileTime.Core;
|
||||||
|
|
||||||
|
public static class Startup
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddCoreDependencies(this IServiceCollection serviceCollection)
|
||||||
|
=> serviceCollection
|
||||||
|
.AddCoreServices()
|
||||||
|
.AddTimelineServices()
|
||||||
|
.AddDefaultCommandHandlers()
|
||||||
|
.AddCommands()
|
||||||
|
.AddCommandFactories()
|
||||||
|
.AddCommandServices()
|
||||||
|
.AddContentAccessServices()
|
||||||
|
.AddSerialization();
|
||||||
|
|
||||||
|
private static IServiceCollection AddContentAccessServices(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
|
||||||
|
serviceCollection.TryAddSingleton<IContentProviderRegistry, ContentProviderRegistry>();
|
||||||
|
serviceCollection.TryAddSingleton<IRootContentProvider, RootContentProvider>();
|
||||||
|
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddCommandServices(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
|
||||||
|
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddCoreServices(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.TryAddTransient<ITab, Tab>();
|
||||||
|
serviceCollection.TryAddSingleton<ITabEvents, TabEvents>();
|
||||||
|
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddTimelineServices(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.TryAddSingleton<ICommandScheduler, CommandScheduler>();
|
||||||
|
serviceCollection.TryAddSingleton<ITimelessContentProvider, TimelessContentProvider>();
|
||||||
|
//TODO: check local/remote context
|
||||||
|
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
|
||||||
|
serviceCollection.TryAddSingleton<ICommandSchedulerNotifier, LocalCommandSchedulerNotifier>();
|
||||||
|
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddCommands(this IServiceCollection serviceCollection)
|
||||||
|
=> serviceCollection
|
||||||
|
.AddTransient<CreateContainerCommand>()
|
||||||
|
.AddTransient<CreateElementCommand>()
|
||||||
|
.AddTransient<DeleteCommand>();
|
||||||
|
|
||||||
|
private static IServiceCollection AddCommandFactories(this IServiceCollection serviceCollection) =>
|
||||||
|
serviceCollection
|
||||||
|
.AddSingleton<CopyCommandFactory>()
|
||||||
|
.AddSingleton<MoveCommandFactory>();
|
||||||
|
|
||||||
|
|
||||||
|
private static IServiceCollection AddSerialization(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.TryAddSingleton<ISerializer<IContainer>, ContainerSerializer>();
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddDefaultCommandHandlers(this IServiceCollection serviceCollection)
|
||||||
|
=> serviceCollection
|
||||||
|
.AddSingleton<ICommandHandler, StreamCopyCommandHandler>();
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization;
|
||||||
|
|
||||||
|
public class AbsolutePathSerializer
|
||||||
|
{
|
||||||
|
public static SerializedAbsolutePath Serialize(AbsolutePath absolutePath)
|
||||||
|
=> new()
|
||||||
|
{
|
||||||
|
PointInTime = absolutePath.PointInTime,
|
||||||
|
Path = absolutePath.Path.Path,
|
||||||
|
Type = absolutePath.Type
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization.Container;
|
||||||
|
|
||||||
|
public record ContainerDeserializationContext(IContentProvider ContentProvider);
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization.Container;
|
||||||
|
|
||||||
|
public record ContainerDeserializationResult(
|
||||||
|
Models.Container Container,
|
||||||
|
ObservableCollection<Exception> Exceptions,
|
||||||
|
ExtensionCollection Extensions,
|
||||||
|
ObservableCollection<AbsolutePath> Items);
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization.Container;
|
||||||
|
|
||||||
|
public class ContainerDeserializer
|
||||||
|
{
|
||||||
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
|
|
||||||
|
public ContainerDeserializer(ITimelessContentProvider timelessContentProvider)
|
||||||
|
{
|
||||||
|
_timelessContentProvider = timelessContentProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerDeserializationResult Deserialize(
|
||||||
|
SerializedContainer source,
|
||||||
|
ContainerDeserializationContext context)
|
||||||
|
{
|
||||||
|
ObservableCollection<Exception> exceptions = new();
|
||||||
|
ExtensionCollection extensions = new();
|
||||||
|
ObservableCollection<AbsolutePath> items = new();
|
||||||
|
|
||||||
|
var mappedItems = source.Items
|
||||||
|
.Select(x => new AbsolutePath(
|
||||||
|
_timelessContentProvider,
|
||||||
|
x.PointInTime,
|
||||||
|
new FullName(x.Path),
|
||||||
|
x.Type
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach (var item in
|
||||||
|
mappedItems)
|
||||||
|
{
|
||||||
|
items.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = new Models.Container(
|
||||||
|
source.Name,
|
||||||
|
source.DisplayName,
|
||||||
|
new FullName(source.FullName),
|
||||||
|
new NativePath(source.NativePath),
|
||||||
|
new AbsolutePath(_timelessContentProvider, PointInTime.Present, new FullName(source.Parent), AbsolutePathType.Container),
|
||||||
|
source.IsHidden,
|
||||||
|
source.IsExists,
|
||||||
|
source.CreatedAt,
|
||||||
|
source.ModifiedAt,
|
||||||
|
source.CanDelete,
|
||||||
|
source.CanRename,
|
||||||
|
source.Attributes,
|
||||||
|
context.ContentProvider,
|
||||||
|
source.AllowRecursiveDeletion,
|
||||||
|
PointInTime.Present,
|
||||||
|
exceptions,
|
||||||
|
new ReadOnlyExtensionCollection(extensions),
|
||||||
|
items
|
||||||
|
);
|
||||||
|
|
||||||
|
return new ContainerDeserializationResult(
|
||||||
|
container,
|
||||||
|
exceptions,
|
||||||
|
extensions,
|
||||||
|
items);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization.Container;
|
||||||
|
|
||||||
|
public class ContainerSerializer : ISerializer<IContainer>
|
||||||
|
{
|
||||||
|
Task<ISerialized> ISerializer<IContainer>.SerializeAsync(int id, IContainer item) => Task.FromResult(Serialize(id, item));
|
||||||
|
|
||||||
|
private ISerialized Serialize(int id, IContainer container)
|
||||||
|
{
|
||||||
|
var items = container.Items.Select(AbsolutePathSerializer.Serialize).ToArray();
|
||||||
|
var serialized = new SerializedContainer
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Name = container.Name,
|
||||||
|
DisplayName = container.DisplayName,
|
||||||
|
FullName = container.FullName!.Path,
|
||||||
|
NativePath = container.NativePath!.Path,
|
||||||
|
Parent = container.Parent!.Path.Path,
|
||||||
|
IsHidden = container.IsHidden,
|
||||||
|
IsExists = container.IsExists,
|
||||||
|
CreatedAt = container.CreatedAt,
|
||||||
|
ModifiedAt = container.ModifiedAt,
|
||||||
|
CanDelete = container.CanDelete,
|
||||||
|
CanRename = container.CanRename,
|
||||||
|
Attributes = container.Attributes,
|
||||||
|
AllowRecursiveDeletion = container.AllowRecursiveDeletion,
|
||||||
|
Items = items
|
||||||
|
};
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization.Container;
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
[MessagePackObject]
|
||||||
|
public class SerializedContainer : ISerialized
|
||||||
|
{
|
||||||
|
[Key(0)] [DataMember(Order = 0)] public required int Id { get; set; }
|
||||||
|
[Key(1)] [DataMember(Order = 1)] public required string Name { get; set; }
|
||||||
|
|
||||||
|
[Key(2)] [DataMember(Order = 2)] public required string DisplayName { get; set; }
|
||||||
|
|
||||||
|
[Key(3)] [DataMember(Order = 3)] public required string FullName { get; set; }
|
||||||
|
|
||||||
|
[Key(4)] [DataMember(Order = 4)] public required string NativePath { get; set; }
|
||||||
|
[Key(5)] [DataMember(Order = 5)] public required string Parent { get; set; }
|
||||||
|
[Key(6)] [DataMember(Order = 6)] public required bool IsHidden { get; set; }
|
||||||
|
[Key(7)] [DataMember(Order = 7)] public required bool IsExists { get; set; }
|
||||||
|
[Key(8)] [DataMember(Order = 8)] public required DateTime? CreatedAt { get; set; }
|
||||||
|
[Key(9)] [DataMember(Order = 9)] public required DateTime? ModifiedAt { get; set; }
|
||||||
|
[Key(10)] [DataMember(Order = 10)] public required SupportsDelete CanDelete { get; set; }
|
||||||
|
[Key(11)] [DataMember(Order = 11)] public required bool CanRename { get; set; }
|
||||||
|
[Key(12)] [DataMember(Order = 12)] public required string? Attributes { get; set; }
|
||||||
|
[Key(13)] [DataMember(Order = 13)] public required bool AllowRecursiveDeletion { get; set; }
|
||||||
|
[Key(14)] [DataMember(Order = 14)] public required SerializedAbsolutePath[] Items { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Core.Models\FileTime.Core.Models.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MessagePack" Version="2.5.124" />
|
||||||
|
<PackageReference Include="MessagePackAnalyzer" Version="2.5.124">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
||||||
9
src/Core/FileTime.Core.Serialization/ISerialized.cs
Normal file
9
src/Core/FileTime.Core.Serialization/ISerialized.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using FileTime.Core.Serialization.Container;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization;
|
||||||
|
|
||||||
|
[MessagePack.Union(0, typeof(SerializedContainer))]
|
||||||
|
public interface ISerialized
|
||||||
|
{
|
||||||
|
int Id { get; }
|
||||||
|
}
|
||||||
14
src/Core/FileTime.Core.Serialization/ISerializer.cs
Normal file
14
src/Core/FileTime.Core.Serialization/ISerializer.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization;
|
||||||
|
|
||||||
|
public interface ISerializer
|
||||||
|
{
|
||||||
|
Task<ISerialized> SerializeAsync(int id, object item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISerializer<T> where T : IItem
|
||||||
|
{
|
||||||
|
async Task<ISerialized> SerializeAsync(int id, object item) => await SerializeAsync(id, (T) item);
|
||||||
|
Task<ISerialized> SerializeAsync(int id, T item);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
[DataContract]
|
||||||
|
public class SerializedAbsolutePath
|
||||||
|
{
|
||||||
|
[Key(0)] [DataMember(Order = 0)] public required PointInTime PointInTime { get; set; }
|
||||||
|
[Key(1)] [DataMember(Order = 1)] public required string Path { get; set; }
|
||||||
|
[Key(2)] [DataMember(Order = 2)] public required AbsolutePathType Type { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization.Timeline;
|
||||||
|
|
||||||
|
public class PointInTimeSerializer
|
||||||
|
{
|
||||||
|
public static SerializedPointInTime Serialize(PointInTime pointInTime)
|
||||||
|
{
|
||||||
|
return new();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Serialization.Timeline;
|
||||||
|
|
||||||
|
public class SerializedDifference
|
||||||
|
{
|
||||||
|
public required SerializedAbsolutePath AbsolutePath { get; set; }
|
||||||
|
public required DifferenceActionType Action { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace FileTime.Core.Serialization.Timeline;
|
||||||
|
|
||||||
|
public class SerializedPointInTime
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -188,7 +188,17 @@ public class Tab : ITab
|
|||||||
|
|
||||||
private static IItem MapItem(AbsolutePath item)
|
private static IItem MapItem(AbsolutePath item)
|
||||||
{
|
{
|
||||||
var t = Task.Run(async () => await item.ResolveAsync(true));
|
var t = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await item.ResolveAsync(true);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
t.Wait();
|
t.Wait();
|
||||||
return t.Result;
|
return t.Result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,6 +139,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Providers.Smb", "P
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Providers.Smb.Abstractions", "Providers\FileTime.Providers.Smb.Abstractions\FileTime.Providers.Smb.Abstractions.csproj", "{595F736D-4711-4AD3-8D4F-13DD85FB35E7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Providers.Smb.Abstractions", "Providers\FileTime.Providers.Smb.Abstractions\FileTime.Providers.Smb.Abstractions.csproj", "{595F736D-4711-4AD3-8D4F-13DD85FB35E7}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Core.Serialization", "Core\FileTime.Core.Serialization\FileTime.Core.Serialization.csproj", "{0AAC0BDF-35F2-434C-882E-047415D55682}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Core.Extensions.DependencyInjection", "Core\FileTime.Core.Extensions.DependencyInjection\FileTime.Core.Extensions.DependencyInjection.csproj", "{0A29616B-5413-4DA9-96EC-B45D6AF632C9}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Server.Tracker", "Server\FileTime.Server.Tracker\FileTime.Server.Tracker.csproj", "{BD382403-86D8-4E99-B279-370FC22F059C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Server.Extensions.DependencyInjection", "Server\FileTime.Server.Extensions.DependencyInjection\FileTime.Server.Extensions.DependencyInjection.csproj", "{25AA9F04-EEEE-49C4-870B-CDFF71717687}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -381,6 +389,22 @@ Global
|
|||||||
{595F736D-4711-4AD3-8D4F-13DD85FB35E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{595F736D-4711-4AD3-8D4F-13DD85FB35E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{595F736D-4711-4AD3-8D4F-13DD85FB35E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{595F736D-4711-4AD3-8D4F-13DD85FB35E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{595F736D-4711-4AD3-8D4F-13DD85FB35E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
{595F736D-4711-4AD3-8D4F-13DD85FB35E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0AAC0BDF-35F2-434C-882E-047415D55682}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0AAC0BDF-35F2-434C-882E-047415D55682}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0AAC0BDF-35F2-434C-882E-047415D55682}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0AAC0BDF-35F2-434C-882E-047415D55682}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0A29616B-5413-4DA9-96EC-B45D6AF632C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0A29616B-5413-4DA9-96EC-B45D6AF632C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0A29616B-5413-4DA9-96EC-B45D6AF632C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0A29616B-5413-4DA9-96EC-B45D6AF632C9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BD382403-86D8-4E99-B279-370FC22F059C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BD382403-86D8-4E99-B279-370FC22F059C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BD382403-86D8-4E99-B279-370FC22F059C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BD382403-86D8-4E99-B279-370FC22F059C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{25AA9F04-EEEE-49C4-870B-CDFF71717687}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{25AA9F04-EEEE-49C4-870B-CDFF71717687}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{25AA9F04-EEEE-49C4-870B-CDFF71717687}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{25AA9F04-EEEE-49C4-870B-CDFF71717687}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -446,6 +470,10 @@ Global
|
|||||||
{CA48A181-256E-4546-B164-6768B240BFFC} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
{CA48A181-256E-4546-B164-6768B240BFFC} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
||||||
{CC8AA3FC-7A5B-4558-AB35-DFF59F2AEF47} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
{CC8AA3FC-7A5B-4558-AB35-DFF59F2AEF47} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
||||||
{595F736D-4711-4AD3-8D4F-13DD85FB35E7} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
{595F736D-4711-4AD3-8D4F-13DD85FB35E7} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
||||||
|
{0AAC0BDF-35F2-434C-882E-047415D55682} = {3324D046-1E05-46B5-B1BA-82910D56B332}
|
||||||
|
{0A29616B-5413-4DA9-96EC-B45D6AF632C9} = {3324D046-1E05-46B5-B1BA-82910D56B332}
|
||||||
|
{BD382403-86D8-4E99-B279-370FC22F059C} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
||||||
|
{25AA9F04-EEEE-49C4-870B-CDFF71717687} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using FileTime.GuiApp.App;
|
|||||||
using FileTime.GuiApp.App.Font;
|
using FileTime.GuiApp.App.Font;
|
||||||
using FileTime.GuiApp.App.ViewModels;
|
using FileTime.GuiApp.App.ViewModels;
|
||||||
using FileTime.GuiApp.App.Views;
|
using FileTime.GuiApp.App.Views;
|
||||||
|
using FileTime.Server;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server.Common;
|
||||||
using FileTime.Tools.Compression;
|
using FileTime.Tools.Compression;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -31,7 +32,7 @@ public class Application : Avalonia.Application
|
|||||||
.AddCompression()
|
.AddCompression()
|
||||||
.ConfigureFont(configuration)
|
.ConfigureFont(configuration)
|
||||||
.RegisterLogging()
|
.RegisterLogging()
|
||||||
.RegisterServices()
|
.RegisterGuiServices()
|
||||||
.AddSettings()
|
.AddSettings()
|
||||||
.AddViewModels()
|
.AddViewModels()
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Search\FileTime.App.Search.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Search\FileTime.App.Search.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\Server\FileTime.Server.Extensions.DependencyInjection\FileTime.Server.Extensions.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\..\..\Tools\FileTime.Tools.Compression\FileTime.Tools.Compression.csproj" />
|
<ProjectReference Include="..\..\..\Tools\FileTime.Tools.Compression\FileTime.Tools.Compression.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp.CustomImpl\FileTime.GuiApp.CustomImpl.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp.CustomImpl\FileTime.GuiApp.CustomImpl.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp.Font\FileTime.GuiApp.Font.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp.Font\FileTime.GuiApp.Font.csproj" />
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public static class Startup
|
|||||||
return serviceCollection;
|
return serviceCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceCollection RegisterServices(this IServiceCollection serviceCollection)
|
internal static IServiceCollection RegisterGuiServices(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
serviceCollection.TryAddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>();
|
serviceCollection.TryAddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>();
|
||||||
serviceCollection.TryAddSingleton<IKeyInputHandlerService, KeyInputHandlerService>();
|
serviceCollection.TryAddSingleton<IKeyInputHandlerService, KeyInputHandlerService>();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace FileTime.Providers.LocalAdmin;
|
|||||||
|
|
||||||
public class AdminElevationManager : IAdminElevationManager, INotifyPropertyChanged, IExitHandler
|
public class AdminElevationManager : IAdminElevationManager, INotifyPropertyChanged, IExitHandler
|
||||||
{
|
{
|
||||||
|
private const string AdminContentProviderName = "localAdminRemote";
|
||||||
private class ConnectionInfo
|
private class ConnectionInfo
|
||||||
{
|
{
|
||||||
public string? SignalRBaseUrl { get; init; }
|
public string? SignalRBaseUrl { get; init; }
|
||||||
@@ -144,9 +145,10 @@ public class AdminElevationManager : IAdminElevationManager, INotifyPropertyChan
|
|||||||
|
|
||||||
_remoteContentProvider = new RemoteContentProvider(
|
_remoteContentProvider = new RemoteContentProvider(
|
||||||
_timelessContentProvider,
|
_timelessContentProvider,
|
||||||
async () => await SignalRConnection.GetOrCreateForAsync(_connectionInfo.SignalRBaseUrl),
|
_serviceProvider,
|
||||||
|
async () => await SignalRConnection.GetOrCreateForAsync(_connectionInfo.SignalRBaseUrl, AdminContentProviderName),
|
||||||
"local",
|
"local",
|
||||||
"localAdminRemote"
|
AdminContentProviderName
|
||||||
);
|
);
|
||||||
|
|
||||||
return Task.FromResult((IRemoteContentProvider)_remoteContentProvider);
|
return Task.FromResult((IRemoteContentProvider)_remoteContentProvider);
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ public interface IRemoteContentProvider : IContentProvider
|
|||||||
{
|
{
|
||||||
Task<IRemoteConnection> GetRemoteConnectionAsync();
|
Task<IRemoteConnection> GetRemoteConnectionAsync();
|
||||||
string RemoteProviderName { get; }
|
string RemoteProviderName { get; }
|
||||||
|
Task InitializeChildren();
|
||||||
}
|
}
|
||||||
@@ -1,47 +1,101 @@
|
|||||||
using FileTime.Core.ContentAccess;
|
using FileTime.Core.ContentAccess;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Serialization.Container;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server.Common;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.Providers.Remote;
|
namespace FileTime.Providers.Remote;
|
||||||
|
|
||||||
public sealed class RemoteContentProvider : ContentProviderBase, IRemoteContentProvider
|
public sealed class RemoteContentProvider : ContentProviderBase, IRemoteContentProvider
|
||||||
{
|
{
|
||||||
public string RemoteProviderName { get; }
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly Func<Task<IRemoteConnection>> _remoteConnectionProvider;
|
private readonly Func<Task<IRemoteConnection>> _remoteConnectionProvider;
|
||||||
|
private readonly SemaphoreSlim _initializeSemaphore = new(1, 1);
|
||||||
|
private bool _initialized;
|
||||||
|
|
||||||
|
public string RemoteProviderName { get; }
|
||||||
|
|
||||||
public RemoteContentProvider(
|
public RemoteContentProvider(
|
||||||
ITimelessContentProvider timelessContentProvider,
|
ITimelessContentProvider timelessContentProvider,
|
||||||
|
IServiceProvider serviceProvider,
|
||||||
Func<Task<IRemoteConnection>> remoteConnectionProvider,
|
Func<Task<IRemoteConnection>> remoteConnectionProvider,
|
||||||
string remoteName,
|
string remoteName,
|
||||||
string name)
|
string name)
|
||||||
: base(name, timelessContentProvider)
|
: base(name, timelessContentProvider)
|
||||||
{
|
{
|
||||||
RemoteProviderName = remoteName;
|
RemoteProviderName = remoteName;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
_remoteConnectionProvider = remoteConnectionProvider;
|
_remoteConnectionProvider = remoteConnectionProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IRemoteConnection> GetRemoteConnectionAsync()
|
public async Task<IRemoteConnection> GetRemoteConnectionAsync()
|
||||||
=> await _remoteConnectionProvider();
|
=> await _remoteConnectionProvider();
|
||||||
|
|
||||||
|
public async Task InitializeChildren()
|
||||||
|
{
|
||||||
|
await _initializeSemaphore.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_initialized) return;
|
||||||
|
|
||||||
|
//TODO: loading indicator
|
||||||
|
|
||||||
|
var connection = await GetRemoteConnectionAsync();
|
||||||
|
var children = await connection.GetChildren(RemoteProviderName, RemoteProviderName);
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_initializeSemaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//TODO implement
|
//TODO implement
|
||||||
public override Task<IItem> GetItemByNativePathAsync(
|
public override async Task<IItem> GetItemByNativePathAsync(
|
||||||
NativePath nativePath,
|
NativePath nativePath,
|
||||||
PointInTime pointInTime,
|
PointInTime pointInTime,
|
||||||
bool forceResolve = false,
|
bool forceResolve = false,
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
ItemInitializationSettings itemInitializationSettings = default) =>
|
ItemInitializationSettings itemInitializationSettings = default)
|
||||||
throw new NotImplementedException();
|
{
|
||||||
|
if (nativePath.Path == string.Empty)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var connection = await GetRemoteConnectionAsync();
|
||||||
|
var serialized = await connection.GetItemByNativePathAsync(
|
||||||
|
RemoteProviderName,
|
||||||
|
nativePath,
|
||||||
|
pointInTime,
|
||||||
|
forceResolve,
|
||||||
|
forceResolvePathType,
|
||||||
|
itemInitializationSettings
|
||||||
|
);
|
||||||
|
|
||||||
|
if (serialized is SerializedContainer serializedContainer)
|
||||||
|
{
|
||||||
|
var containerDeserializer = _serviceProvider.GetRequiredService<ContainerDeserializer>();
|
||||||
|
var container = containerDeserializer.Deserialize(
|
||||||
|
serializedContainer,
|
||||||
|
new ContainerDeserializationContext(this)
|
||||||
|
);
|
||||||
|
|
||||||
|
return container.Container;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: make it async
|
|
||||||
public override async ValueTask<NativePath> GetNativePathAsync(FullName fullName)
|
public override async ValueTask<NativePath> GetNativePathAsync(FullName fullName)
|
||||||
{
|
{
|
||||||
var remoteFullname = new FullName(ConvertLocalFullNameToRemote(fullName));
|
var remoteFullname = new FullName(ConvertLocalFullNameToRemote(fullName));
|
||||||
|
|
||||||
var connection = await GetRemoteConnectionAsync();
|
var connection = await GetRemoteConnectionAsync();
|
||||||
var remoteNativePath = await connection.GetNativePathAsync(remoteFullname);
|
var remoteNativePath = await connection.GetNativePathAsync(RemoteProviderName, remoteFullname);
|
||||||
return new NativePath(remoteNativePath!.Path);
|
return new NativePath(remoteNativePath.Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
public override FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Serialization\FileTime.Core.Serialization.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Serialization;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
namespace FileTime.Server.Common;
|
namespace FileTime.Server.Common;
|
||||||
|
|
||||||
@@ -13,5 +16,17 @@ 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);
|
Task<NativePath> GetNativePathAsync(string contentProviderId, FullName fullName);
|
||||||
|
|
||||||
|
Task<ISerialized> GetItemByNativePathAsync(
|
||||||
|
string contentProviderId,
|
||||||
|
NativePath nativePath,
|
||||||
|
PointInTime pointInTime,
|
||||||
|
bool forceResolve,
|
||||||
|
AbsolutePathType forceResolvePathType,
|
||||||
|
ItemInitializationSettings itemInitializationSettings);
|
||||||
|
|
||||||
|
Task<SerializedAbsolutePath[]> GetChildren(
|
||||||
|
string contentProviderId,
|
||||||
|
string fullName);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Server.Common.ItemTracker;
|
||||||
|
|
||||||
|
public interface IItemTrackerRegistry
|
||||||
|
{
|
||||||
|
int Register(IItem item);
|
||||||
|
event Action<int>? ItemRemoved;
|
||||||
|
}
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
public interface ISignalRClient
|
public interface ISignalRClient
|
||||||
{
|
{
|
||||||
|
Task RemoveTrackedItem(int itemId);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
namespace FileTime.Server.Common.Connections.SignalR;
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Serialization;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
|
namespace FileTime.Server.Common.Connections.SignalR;
|
||||||
|
|
||||||
public interface ISignalRHub
|
public interface ISignalRHub
|
||||||
{
|
{
|
||||||
|
Task SetClientIdentifier(string providerName);
|
||||||
Task Exit();
|
Task Exit();
|
||||||
Task CreateContainerAsync(string contentProviderId, string fullName);
|
Task CreateContainerAsync(string contentProviderId, string fullName);
|
||||||
Task CreateElementAsync(string contentProviderId, string fullName);
|
Task CreateElementAsync(string contentProviderId, string fullName);
|
||||||
@@ -15,5 +21,16 @@ 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);
|
Task<string> GetNativePathAsync(string contentProviderId, string fullNamePath);
|
||||||
|
Task<ISerialized> GetItemByNativePathAsync(
|
||||||
|
string contentProviderId,
|
||||||
|
NativePath nativePath,
|
||||||
|
PointInTime pointInTime,
|
||||||
|
bool forceResolve,
|
||||||
|
AbsolutePathType forceResolvePathType,
|
||||||
|
ItemInitializationSettings itemInitializationSettings);
|
||||||
|
|
||||||
|
Task<SerializedAbsolutePath[]> GetChildren(
|
||||||
|
string contentProviderId,
|
||||||
|
string fullName);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Serialization;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
@@ -6,7 +9,7 @@ using TypedSignalR.Client;
|
|||||||
|
|
||||||
namespace FileTime.Server.Common.Connections.SignalR;
|
namespace FileTime.Server.Common.Connections.SignalR;
|
||||||
|
|
||||||
public class SignalRConnection : IRemoteConnection, IAsyncInitable<string>
|
public class SignalRConnection : IRemoteConnection, IAsyncInitable<string, string>
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, SignalRConnection> Connections = new();
|
private static readonly Dictionary<string, SignalRConnection> Connections = new();
|
||||||
private static readonly object ConnectionsLock = new();
|
private static readonly object ConnectionsLock = new();
|
||||||
@@ -15,7 +18,7 @@ public class SignalRConnection : IRemoteConnection, IAsyncInitable<string>
|
|||||||
private HubConnection _connection = null!;
|
private HubConnection _connection = null!;
|
||||||
private ISignalRHub _client = null!;
|
private ISignalRHub _client = null!;
|
||||||
|
|
||||||
public async Task InitAsync(string baseUrl)
|
public async Task InitAsync(string baseUrl, string providerName)
|
||||||
{
|
{
|
||||||
_baseUrl = baseUrl;
|
_baseUrl = baseUrl;
|
||||||
|
|
||||||
@@ -26,9 +29,10 @@ public class SignalRConnection : IRemoteConnection, IAsyncInitable<string>
|
|||||||
_connection = connectionBuilder.Build();
|
_connection = connectionBuilder.Build();
|
||||||
await _connection.StartAsync();
|
await _connection.StartAsync();
|
||||||
_client = _connection.CreateHubProxy<ISignalRHub>();
|
_client = _connection.CreateHubProxy<ISignalRHub>();
|
||||||
|
await _client.SetClientIdentifier(providerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<SignalRConnection> GetOrCreateForAsync(string baseUrl)
|
public static async Task<SignalRConnection> GetOrCreateForAsync(string baseUrl, string providerName)
|
||||||
{
|
{
|
||||||
SignalRConnection? connection;
|
SignalRConnection? connection;
|
||||||
lock (ConnectionsLock)
|
lock (ConnectionsLock)
|
||||||
@@ -47,7 +51,7 @@ public class SignalRConnection : IRemoteConnection, IAsyncInitable<string>
|
|||||||
Connections.Add(baseUrl, connection);
|
Connections.Add(baseUrl, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
await connection.InitAsync(baseUrl);
|
await connection.InitAsync(baseUrl, providerName);
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,9 +82,32 @@ 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)
|
public async Task<NativePath> GetNativePathAsync(string contentProviderId, FullName fullName)
|
||||||
{
|
{
|
||||||
var path = await _client.GetNativePathAsync(fullName.Path);
|
var path = await _client.GetNativePathAsync(contentProviderId, fullName.Path);
|
||||||
return path is null ? null : new NativePath(path);
|
return new NativePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ISerialized> GetItemByNativePathAsync(
|
||||||
|
string contentProviderId,
|
||||||
|
NativePath nativePath,
|
||||||
|
PointInTime pointInTime,
|
||||||
|
bool forceResolve,
|
||||||
|
AbsolutePathType forceResolvePathType,
|
||||||
|
ItemInitializationSettings itemInitializationSettings)
|
||||||
|
{
|
||||||
|
var item = await _client.GetItemByNativePathAsync(
|
||||||
|
contentProviderId,
|
||||||
|
nativePath,
|
||||||
|
pointInTime,
|
||||||
|
forceResolve,
|
||||||
|
forceResolvePathType,
|
||||||
|
itemInitializationSettings
|
||||||
|
);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SerializedAbsolutePath[]> GetChildren(string contentProviderId, string fullName)
|
||||||
|
=> await _client.GetChildren(contentProviderId, fullName);
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Serialization\FileTime.Core.Serialization.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.Server.Common.Abstractions\FileTime.Server.Common.Abstractions.csproj" />
|
<ProjectReference Include="..\FileTime.Server.Common.Abstractions\FileTime.Server.Common.Abstractions.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using FileTime.Server.Common.Connections.SignalR;
|
|
||||||
using FileTime.Server.Common.ContentAccess;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
|
|
||||||
namespace FileTime.Server.Common;
|
|
||||||
|
|
||||||
public static class Startup
|
|
||||||
{
|
|
||||||
public static IServiceCollection AddServerCoreServices(this IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddTransient<SignalRConnection>();
|
|
||||||
services.TryAddSingleton<IApplicationStopper, ApplicationStopper>();
|
|
||||||
services.AddSingleton<IContentAccessManager, ContentAccessManager>();
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>FileTime.Server</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FileTime.Server.Common\FileTime.Server.Common.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Server.Tracker\FileTime.Server.Tracker.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using FileTime.Server.Common;
|
||||||
|
using FileTime.Server.Common.Connections.SignalR;
|
||||||
|
using FileTime.Server.Common.ContentAccess;
|
||||||
|
using FileTime.Server.Common.ItemTracker;
|
||||||
|
using FileTime.Server.Tracker.ItemTracker;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
|
||||||
|
namespace FileTime.Server;
|
||||||
|
|
||||||
|
public static class Startup
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddServerCoreServices(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.AddTransient<SignalRConnection>();
|
||||||
|
serviceCollection.TryAddSingleton<IApplicationStopper, ApplicationStopper>();
|
||||||
|
serviceCollection.TryAddSingleton<IContentAccessManager, ContentAccessManager>();
|
||||||
|
return serviceCollection.AddRemoteTrackerServices();
|
||||||
|
}
|
||||||
|
private static IServiceCollection AddRemoteTrackerServices(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
serviceCollection.TryAddSingleton<IItemTrackerRegistry, ItemTrackerRegistry>();
|
||||||
|
return serviceCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FileTime.Server.Common.Abstractions\FileTime.Server.Common.Abstractions.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Server.Common.ItemTracker;
|
||||||
|
|
||||||
|
namespace FileTime.Server.Tracker.ItemTracker;
|
||||||
|
|
||||||
|
public class ItemTrackerRegistry : IItemTrackerRegistry
|
||||||
|
{
|
||||||
|
private readonly object _lock = new();
|
||||||
|
private readonly Dictionary<int, WeakReference<IItem>> _items = new();
|
||||||
|
|
||||||
|
private int _globalId = 1;
|
||||||
|
public event Action<int>? ItemRemoved;
|
||||||
|
|
||||||
|
public int Register(IItem item)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
while (_items.ContainsKey(_globalId)) _globalId++;
|
||||||
|
_items[_globalId] = new WeakReference<IItem>(item);
|
||||||
|
return _globalId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Clean()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
var keys = _items.Keys.ToArray();
|
||||||
|
var keysToRemove = new List<int>();
|
||||||
|
foreach (var key in keys)
|
||||||
|
{
|
||||||
|
if (!_items[key].TryGetTarget(out _))
|
||||||
|
{
|
||||||
|
keysToRemove.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var key in keysToRemove)
|
||||||
|
{
|
||||||
|
_items.Remove(key);
|
||||||
|
ItemRemoved?.Invoke(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
using FileTime.Core.ContentAccess;
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Serialization;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server.Common;
|
||||||
using FileTime.Server.Common.Connections.SignalR;
|
using FileTime.Server.Common.Connections.SignalR;
|
||||||
using FileTime.Server.Common.ContentAccess;
|
using FileTime.Server.Common.ContentAccess;
|
||||||
|
using FileTime.Server.Common.ItemTracker;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.Server.Web;
|
namespace FileTime.Server.Web;
|
||||||
|
|
||||||
@@ -14,20 +18,46 @@ 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;
|
private readonly IItemTrackerRegistry _itemTrackerRegistry;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
private readonly Dictionary<int, string> _trackedItemIds = new();
|
||||||
|
|
||||||
|
//TODO clean this sometimes
|
||||||
|
private readonly Dictionary<string, string> _clientIdToConnectionId = new();
|
||||||
|
|
||||||
public ConnectionHub(
|
public ConnectionHub(
|
||||||
IContentProviderRegistry contentProviderRegistry,
|
IContentProviderRegistry contentProviderRegistry,
|
||||||
IContentAccessorFactory contentAccessorFactory,
|
IContentAccessorFactory contentAccessorFactory,
|
||||||
IApplicationStopper applicationStopper,
|
IApplicationStopper applicationStopper,
|
||||||
IContentAccessManager contentAccessManager,
|
IContentAccessManager contentAccessManager,
|
||||||
ITimelessContentProvider timelessContentProvider)
|
IItemTrackerRegistry itemTrackerRegistry,
|
||||||
|
IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_contentProviderRegistry = contentProviderRegistry;
|
_contentProviderRegistry = contentProviderRegistry;
|
||||||
_contentAccessorFactory = contentAccessorFactory;
|
_contentAccessorFactory = contentAccessorFactory;
|
||||||
_applicationStopper = applicationStopper;
|
_applicationStopper = applicationStopper;
|
||||||
_contentAccessManager = contentAccessManager;
|
_contentAccessManager = contentAccessManager;
|
||||||
_timelessContentProvider = timelessContentProvider;
|
_itemTrackerRegistry = itemTrackerRegistry;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
|
||||||
|
_itemTrackerRegistry.ItemRemoved += ItemTrackerRegistryOnItemRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ItemTrackerRegistryOnItemRemoved(int id)
|
||||||
|
{
|
||||||
|
if (_trackedItemIds.ContainsKey(id)) return;
|
||||||
|
|
||||||
|
var clientId = _trackedItemIds[id];
|
||||||
|
var connectionId = _clientIdToConnectionId[clientId];
|
||||||
|
|
||||||
|
Clients.Client(connectionId).RemoveTrackedItem(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SetClientIdentifier(string providerName)
|
||||||
|
{
|
||||||
|
_clientIdToConnectionId[providerName] = Context.ConnectionId;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Exit()
|
public Task Exit()
|
||||||
@@ -39,35 +69,35 @@ public class ConnectionHub : Hub<ISignalRClient>, ISignalRHub
|
|||||||
public async Task CreateContainerAsync(string contentProviderId, string fullName)
|
public async Task CreateContainerAsync(string contentProviderId, string fullName)
|
||||||
{
|
{
|
||||||
//TODO handle no content provider with id
|
//TODO handle no content provider with id
|
||||||
var contentProvider = _contentProviderRegistry.ContentProviders.First(p => p.Name == contentProviderId);
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
var itemCreator = _contentAccessorFactory.GetItemCreator(contentProvider);
|
var itemCreator = _contentAccessorFactory.GetItemCreator(contentProvider);
|
||||||
await itemCreator.CreateContainerAsync(contentProvider, new FullName(fullName));
|
await itemCreator.CreateContainerAsync(contentProvider, new FullName(fullName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateElementAsync(string contentProviderId, string fullName)
|
public async Task CreateElementAsync(string contentProviderId, string fullName)
|
||||||
{
|
{
|
||||||
var contentProvider = _contentProviderRegistry.ContentProviders.First(p => p.Name == contentProviderId);
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
var itemCreator = _contentAccessorFactory.GetItemCreator(contentProvider);
|
var itemCreator = _contentAccessorFactory.GetItemCreator(contentProvider);
|
||||||
await itemCreator.CreateElementAsync(contentProvider, new FullName(fullName));
|
await itemCreator.CreateElementAsync(contentProvider, new FullName(fullName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteItemAsync(string contentProviderId, string fullName)
|
public async Task DeleteItemAsync(string contentProviderId, string fullName)
|
||||||
{
|
{
|
||||||
var contentProvider = _contentProviderRegistry.ContentProviders.First(p => p.Name == contentProviderId);
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
var itemDeleter = _contentAccessorFactory.GetItemDeleter(contentProvider);
|
var itemDeleter = _contentAccessorFactory.GetItemDeleter(contentProvider);
|
||||||
await itemDeleter.DeleteAsync(contentProvider, new FullName(fullName));
|
await itemDeleter.DeleteAsync(contentProvider, new FullName(fullName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MoveItemAsync(string contentProviderId, string fullName, string newPath)
|
public async Task MoveItemAsync(string contentProviderId, string fullName, string newPath)
|
||||||
{
|
{
|
||||||
var contentProvider = _contentProviderRegistry.ContentProviders.First(p => p.Name == contentProviderId);
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
var itemDeleter = _contentAccessorFactory.GetItemMover(contentProvider);
|
var itemDeleter = _contentAccessorFactory.GetItemMover(contentProvider);
|
||||||
await itemDeleter.RenameAsync(contentProvider, new FullName(fullName), new FullName(newPath));
|
await itemDeleter.RenameAsync(contentProvider, new FullName(fullName), new FullName(newPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InitializeRemoteWriter(string contentProviderId, string transactionId, string nativePath)
|
public async Task InitializeRemoteWriter(string contentProviderId, string transactionId, string nativePath)
|
||||||
{
|
{
|
||||||
var contentProvider = _contentProviderRegistry.ContentProviders.First(p => p.Name == contentProviderId);
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
var item = await contentProvider.GetItemByNativePathAsync(new NativePath(nativePath), PointInTime.Present);
|
var item = await contentProvider.GetItemByNativePathAsync(new NativePath(nativePath), PointInTime.Present);
|
||||||
if (item is not IElement element)
|
if (item is not IElement element)
|
||||||
throw new FileNotFoundException("Item is not an element", nativePath);
|
throw new FileNotFoundException("Item is not an element", nativePath);
|
||||||
@@ -90,6 +120,55 @@ public class ConnectionHub : Hub<ISignalRClient>, ISignalRHub
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> GetNativePathAsync(string fullNamePath)
|
public async Task<string> GetNativePathAsync(string contentProviderId, string fullNamePath)
|
||||||
=> (await _timelessContentProvider.GetNativePathByFullNameAsync(new FullName(fullNamePath)))?.Path;
|
{
|
||||||
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
|
return (await contentProvider.GetNativePathAsync(new FullName(fullNamePath))).Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ISerialized> GetItemByNativePathAsync(
|
||||||
|
string contentProviderId,
|
||||||
|
NativePath nativePath,
|
||||||
|
PointInTime pointInTime,
|
||||||
|
bool forceResolve,
|
||||||
|
AbsolutePathType forceResolvePathType,
|
||||||
|
ItemInitializationSettings itemInitializationSettings)
|
||||||
|
{
|
||||||
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
|
var item = await contentProvider.GetItemByNativePathAsync(
|
||||||
|
nativePath,
|
||||||
|
pointInTime,
|
||||||
|
forceResolve,
|
||||||
|
forceResolvePathType,
|
||||||
|
itemInitializationSettings
|
||||||
|
);
|
||||||
|
|
||||||
|
var id = _itemTrackerRegistry.Register(item);
|
||||||
|
|
||||||
|
var serializerType = typeof(ISerializer<>).MakeGenericType(item.GetType());
|
||||||
|
var serializer = (ISerializer) _serviceProvider.GetRequiredService(serializerType);
|
||||||
|
var serializedObject = await serializer.SerializeAsync(id, item);
|
||||||
|
|
||||||
|
return serializedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SerializedAbsolutePath[]> GetChildren(
|
||||||
|
string contentProviderId,
|
||||||
|
string fullName)
|
||||||
|
{
|
||||||
|
var contentProvider = GetContentProvider(contentProviderId);
|
||||||
|
var item = await contentProvider.GetItemByFullNameAsync(
|
||||||
|
new FullName(fullName),
|
||||||
|
PointInTime.Present);
|
||||||
|
|
||||||
|
if (item is IContainer container)
|
||||||
|
return container.Items.Select(AbsolutePathSerializer.Serialize).ToArray();
|
||||||
|
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IContentProvider GetContentProvider(string contentProviderId)
|
||||||
|
=> _contentProviderRegistry
|
||||||
|
.ContentProviders
|
||||||
|
.First(p => p.Name == contentProviderId);
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
<ProjectReference Include="..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
<ProjectReference Include="..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\..\Providers\FileTime.Providers.Local\FileTime.Providers.Local.csproj" />
|
<ProjectReference Include="..\..\Providers\FileTime.Providers.Local\FileTime.Providers.Local.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.Server.App\FileTime.Server.App.csproj" />
|
<ProjectReference Include="..\FileTime.Server.App\FileTime.Server.App.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Server.Extensions.DependencyInjection\FileTime.Server.Extensions.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.Server.Web\FileTime.Server.Web.csproj" />
|
<ProjectReference Include="..\FileTime.Server.Web\FileTime.Server.Web.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Autofac.Extensions.DependencyInjection;
|
using Autofac.Extensions.DependencyInjection;
|
||||||
using FileTime.App.DependencyInjection;
|
using FileTime.App.DependencyInjection;
|
||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
|
using FileTime.Server;
|
||||||
using FileTime.Server.App;
|
using FileTime.Server.App;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server.Common;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|||||||
Reference in New Issue
Block a user