using System.Collections.ObjectModel; using System.Runtime.InteropServices; using FileTime.Core.Models; using FileTime.Core.Timeline; using ObservableComputations; namespace FileTime.Providers.Local; public class RootDriveInfoService : IRootDriveInfoService { private readonly ILocalContentProvider _localContentProvider; private readonly ObservableCollection _rootDrives = new(); private readonly ObservableCollection _allDrives = new(); private readonly OcConsumer _rootDriveInfosConsumer = new(); public ReadOnlyObservableCollection AllDrives { get; set; } public ReadOnlyObservableCollection RootDriveInfos { get; set; } public RootDriveInfoService(ILocalContentProvider localContentProvider) { _localContentProvider = localContentProvider; var (rootDrives, allDrives) = GetRootDrives(); foreach (var driveInfo in rootDrives) { _rootDrives.Add(driveInfo); } foreach (var driveInfo in allDrives) { _allDrives.Add(driveInfo); } var rootDriveInfos = _rootDrives.Selecting(r => GetContainer(r)) .Filtering(t => t.Item != null) .Selecting(t => new RootDriveInfo(t.Drive, t.Item!)) .Ordering(d => GetDriveOrder(d.DriveType)) .ThenOrdering(d => d.Name) .For(_rootDriveInfosConsumer); RootDriveInfos = new ReadOnlyObservableCollection(rootDriveInfos); AllDrives = new ReadOnlyObservableCollection(_allDrives); static (DriveInfo[] RootDrives, DriveInfo[] AllDrives) GetRootDrives() { var allDrives = DriveInfo.GetDrives(); var drives = DriveInfo.GetDrives().Where(d => d.DriveType is not DriveType.Unknown and not DriveType.Ram); drives = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? drives : drives.Where(d => d.TotalSize != 0 && d.DriveFormat != "pstorefs" && d.DriveFormat != "bpf_fs" && d.DriveFormat != "tracefs" && d.DriveFormat != "rpc_pipefs" && !d.RootDirectory.FullName.StartsWith("/snap/")); return (drives.ToArray(), allDrives); } } private (DriveInfo Drive, IContainer? Item) GetContainer(DriveInfo rootDriveInfo) { var container = Task.Run( async () => { try { return await _localContentProvider.GetItemByNativePathAsync( new NativePath(rootDriveInfo.RootDirectory.FullName), PointInTime.Present); } catch { return null; } } ).GetAwaiter().GetResult(); return (rootDriveInfo, container as IContainer); } private static int GetDriveOrder(DriveType type) => type switch { DriveType.Fixed => 0, DriveType.Removable => 1, DriveType.CDRom => 2, DriveType.Network => 3, _ => 5 }; public Task ExitAsync(CancellationToken token = default) { _rootDriveInfosConsumer.Dispose(); return Task.CompletedTask; } }