Added a bit more implementation for the Default TransferProvider.
This commit is contained in:
parent
2c8489de43
commit
e089bfb4d2
|
@ -0,0 +1,8 @@
|
|||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class DownloadClientPath
|
||||
{
|
||||
public int DownloadClientId { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
}
|
|
@ -503,6 +503,7 @@
|
|||
<Compile Include="Download\Clients\uTorrent\UTorrentTorrentStatus.cs" />
|
||||
<Compile Include="Download\Clients\Vuze\Vuze.cs" />
|
||||
<Compile Include="Download\CompletedDownloadService.cs" />
|
||||
<Compile Include="Download\DownloadClientPath.cs" />
|
||||
<Compile Include="Download\DownloadClientStatus.cs" />
|
||||
<Compile Include="Download\DownloadEventHub.cs" />
|
||||
<Compile Include="Download\DownloadClientStatusRepository.cs" />
|
||||
|
@ -947,7 +948,10 @@
|
|||
<Compile Include="Qualities\QualitySource.cs" />
|
||||
<Compile Include="Qualities\Revision.cs" />
|
||||
<Compile Include="TransferProviders\Providers\DefaultTransfer.cs" />
|
||||
<Compile Include="TransferProviders\Providers\DirectVirtualDiskProvider.cs" />
|
||||
<Compile Include="TransferProviders\Providers\Dummy.cs" />
|
||||
<Compile Include="TransferProviders\Providers\EmptyVirtualDiskProvider.cs" />
|
||||
<Compile Include="TransferProviders\Providers\MountVirtualDiskProvider.cs" />
|
||||
<Compile Include="TransferProviders\TransferProviderDefinition.cs" />
|
||||
<Compile Include="TransferProviders\TransferProviderRepository.cs" />
|
||||
<Compile Include="TransferProviders\Providers\CustomTransfer.cs" />
|
||||
|
|
|
@ -7,14 +7,10 @@ namespace NzbDrone.Core.TransferProviders
|
|||
{
|
||||
public interface ITransferProvider : IProvider
|
||||
{
|
||||
// TODO: Perhaps change 'string' to 'DownloadClientPath' struct/class so we're more typesafe.
|
||||
|
||||
// Whether the TransferProvider is ready to be accessed. (Useful for external transfers that may not have finished yet)
|
||||
bool IsAvailable(string downloadClientPath);
|
||||
bool IsAvailable(DownloadClientItem item);
|
||||
bool IsAvailable(DownloadClientPath item);
|
||||
|
||||
// Returns a wrapper for the specific download. Optionally we might want to supply a 'tempDir' that's close to the series path, in case the TransferProvider needs an intermediate location.
|
||||
IVirtualDiskProvider GetFileSystemWrapper(string downloadClientPath);
|
||||
IVirtualDiskProvider GetFileSystemWrapper(DownloadClientItem item);
|
||||
// Returns a wrapper for the specific download. Optionally we might want to supply a 'tempPath' that's close to the series path, in case the TransferProvider needs an intermediate location.
|
||||
IVirtualDiskProvider GetFileSystemWrapper(DownloadClientPath item, string tempPath = null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
@ -16,6 +17,9 @@ namespace NzbDrone.Core.TransferProviders
|
|||
// Returns recursive list of all files in the 'volume'/'filesystem'/'dataset' (whatever we want to call it).
|
||||
string[] GetFiles();
|
||||
|
||||
// Opens a readable stream.
|
||||
Stream OpenFile(string vfsFilePath);
|
||||
|
||||
// Copies file from the virtual filesystem to the actual one.
|
||||
TransferTask CopyFile(string vfsSourcePath, string destinationPath);
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.TransferProviders.Providers
|
||||
|
@ -9,6 +14,19 @@ namespace NzbDrone.Core.TransferProviders.Providers
|
|||
// Represents a local filesystem transfer.
|
||||
class DefaultTransfer : TransferProviderBase<NullConfig>
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDiskTransferService _transferService;
|
||||
|
||||
public override string Name => "Default";
|
||||
|
||||
public DefaultTransfer(IDiskTransferService transferService, IDiskProvider diskProvider, Logger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_diskProvider = diskProvider;
|
||||
_transferService = transferService;
|
||||
}
|
||||
|
||||
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
{
|
||||
get
|
||||
|
@ -23,19 +41,39 @@ namespace NzbDrone.Core.TransferProviders.Providers
|
|||
};
|
||||
}
|
||||
}
|
||||
public override string Link
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override ValidationResult Test()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool IsAvailable(DownloadClientPath item)
|
||||
{
|
||||
if (item == null) return false;
|
||||
|
||||
var path = ResolvePath(item);
|
||||
|
||||
return _diskProvider.FolderExists(path) || _diskProvider.FileExists(path);
|
||||
}
|
||||
|
||||
// TODO: Give DirectVirtualDiskProvider the tempPath.
|
||||
public override IVirtualDiskProvider GetFileSystemWrapper(DownloadClientPath item, string tempPath = null)
|
||||
{
|
||||
var path = ResolvePath(item);
|
||||
|
||||
if (_diskProvider.FolderExists(path) || _diskProvider.FileExists(path))
|
||||
{
|
||||
// Expose a virtual filesystem with only that directory/file in it.
|
||||
// This allows the caller to delete the directory if desired, but not it's siblings.
|
||||
return new DirectVirtualDiskProvider(_diskProvider, _transferService, Path.GetDirectoryName(path), path);
|
||||
}
|
||||
|
||||
return new EmptyVirtualDiskProvider();
|
||||
}
|
||||
|
||||
protected string ResolvePath(DownloadClientPath path)
|
||||
{
|
||||
return path.Path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Timeline;
|
||||
using NzbDrone.Common.TPL;
|
||||
|
||||
namespace NzbDrone.Core.TransferProviders.Providers
|
||||
{
|
||||
public class DirectVirtualDiskProvider : IVirtualDiskProvider
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDiskTransferService _transferService;
|
||||
private readonly string _rootFolder;
|
||||
private readonly List<string> _items;
|
||||
|
||||
public bool SupportStreaming => true;
|
||||
|
||||
public DirectVirtualDiskProvider(IDiskProvider diskProvider, IDiskTransferService transferService, string rootFolder, params string[] items)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_transferService = transferService;
|
||||
_rootFolder = rootFolder;
|
||||
_items = items.ToList();
|
||||
}
|
||||
|
||||
public string[] GetFiles()
|
||||
{
|
||||
return _items.SelectMany(GetFiles).Select(_rootFolder.GetRelativePath).ToArray();
|
||||
}
|
||||
|
||||
private string[] GetFiles(string sourcePath)
|
||||
{
|
||||
if (_diskProvider.FileExists(sourcePath))
|
||||
{
|
||||
return new [] { sourcePath };
|
||||
}
|
||||
else
|
||||
{
|
||||
return _diskProvider.GetFiles(sourcePath, SearchOption.AllDirectories);
|
||||
}
|
||||
}
|
||||
|
||||
public TransferTask MoveFile(string vfsSourcePath, string destinationPath)
|
||||
{
|
||||
return TransferFile(vfsSourcePath, destinationPath, TransferMode.Move);
|
||||
}
|
||||
|
||||
public TransferTask CopyFile(string vfsSourcePath, string destinationPath)
|
||||
{
|
||||
return TransferFile(vfsSourcePath, destinationPath, TransferMode.Copy);
|
||||
}
|
||||
|
||||
private TransferTask TransferFile(string vfsSourcePath, string destinationPath, TransferMode mode)
|
||||
{
|
||||
var sourcePath = ResolveVirtualPath(vfsSourcePath);
|
||||
|
||||
var fileSize = _diskProvider.GetFileSize(sourcePath);
|
||||
var progress = new TimelineContext($"{mode} {Path.GetFileName(sourcePath)}", 0, fileSize);
|
||||
var task = Task.Factory.StartNew(() =>
|
||||
{
|
||||
progress.UpdateState(TimelineState.Started);
|
||||
_transferService.TransferFile(sourcePath, destinationPath, mode);
|
||||
if (mode == TransferMode.Move && _items.Contains(vfsSourcePath))
|
||||
{
|
||||
// If it was moved, then remove it from the list.
|
||||
_items.Remove(vfsSourcePath);
|
||||
}
|
||||
progress.FinishProgress();
|
||||
});
|
||||
|
||||
return new TransferTask(progress, task);
|
||||
}
|
||||
|
||||
public Stream OpenFile(string vfsFilePath)
|
||||
{
|
||||
var sourcePath = ResolveVirtualPath(vfsFilePath);
|
||||
|
||||
return _diskProvider.OpenReadStream(sourcePath);
|
||||
}
|
||||
|
||||
private string ResolveVirtualPath(string virtualPath)
|
||||
{
|
||||
if (Path.IsPathRooted(virtualPath))
|
||||
{
|
||||
throw new InvalidOperationException("Path not valid in the virtual filesystem");
|
||||
}
|
||||
|
||||
var basePath = virtualPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)[0];
|
||||
|
||||
if (!_items.Contains(basePath))
|
||||
{
|
||||
throw new InvalidOperationException("Path not valid in the virtual filesystem");
|
||||
}
|
||||
|
||||
return Path.Combine(_rootFolder, virtualPath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.TransferProviders.Providers
|
||||
{
|
||||
// Marks the files are permanently unavailable. Perhaps useful in fire-and-forget.
|
||||
class Dummy : TransferProviderBase<NullConfig>
|
||||
{
|
||||
public override string Link
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public override ValidationResult Test()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.TransferProviders.Providers
|
||||
{
|
||||
public class EmptyVirtualDiskProvider : IVirtualDiskProvider
|
||||
{
|
||||
public bool SupportStreaming => true;
|
||||
|
||||
|
||||
public string[] GetFiles()
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
public TransferTask MoveFile(string vfsSourcePath, string destinationPath)
|
||||
{
|
||||
throw new FileNotFoundException("File not found in virtual filesystem", vfsSourcePath);
|
||||
}
|
||||
|
||||
public TransferTask CopyFile(string vfsSourcePath, string destinationPath)
|
||||
{
|
||||
throw new FileNotFoundException("File not found in virtual filesystem", vfsSourcePath);
|
||||
}
|
||||
|
||||
public Stream OpenFile(string vfsFilePath)
|
||||
{
|
||||
throw new FileNotFoundException("File not found in virtual filesystem", vfsFilePath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
|
@ -21,19 +25,52 @@ namespace NzbDrone.Core.TransferProviders.Providers
|
|||
|
||||
public class MountTransfer : TransferProviderBase<MountSettings>
|
||||
{
|
||||
public override string Link
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
private readonly Logger _logger;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IDiskTransferService _transferService;
|
||||
|
||||
public override string Name
|
||||
public override string Name => "Mount";
|
||||
|
||||
public MountTransfer(IDiskTransferService transferService, IDiskProvider diskProvider, Logger logger)
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
_logger = logger;
|
||||
_diskProvider = diskProvider;
|
||||
_transferService = transferService;
|
||||
}
|
||||
|
||||
public override ValidationResult Test()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool IsAvailable(DownloadClientPath item)
|
||||
{
|
||||
if (item == null) return false;
|
||||
|
||||
var path = ResolvePath(item);
|
||||
|
||||
return _diskProvider.FolderExists(path) || _diskProvider.FileExists(path);
|
||||
}
|
||||
|
||||
// TODO: Give MountVirtualDiskProvider the tempPath.
|
||||
public override IVirtualDiskProvider GetFileSystemWrapper(DownloadClientPath item, string tempPath = null)
|
||||
{
|
||||
var path = ResolvePath(item);
|
||||
|
||||
if (_diskProvider.FolderExists(path) || _diskProvider.FileExists(path))
|
||||
{
|
||||
// Expose a virtual filesystem with only that directory/file in it.
|
||||
// This allows the caller to delete the directory if desired, but not it's siblings.
|
||||
return new MountVirtualDiskProvider(_diskProvider, _transferService, Path.GetDirectoryName(path), path);
|
||||
}
|
||||
|
||||
return new EmptyVirtualDiskProvider();
|
||||
}
|
||||
|
||||
protected string ResolvePath(DownloadClientPath path)
|
||||
{
|
||||
// Same logic as RemotePathMapping service.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
||||
namespace NzbDrone.Core.TransferProviders.Providers
|
||||
{
|
||||
// Empty wrapper, it would server in dealing with stuff being slower and remote mounts potentially being unavailable temporarily.
|
||||
// Ideally it should wrap a DirectVirtualDiskProvider instance, rather than inheriting from it.
|
||||
public class MountVirtualDiskProvider : DirectVirtualDiskProvider
|
||||
{
|
||||
public MountVirtualDiskProvider(IDiskProvider diskProvider, IDiskTransferService transferService, string rootFolder, params string[] items)
|
||||
: base(diskProvider, transferService, rootFolder, items)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.TransferProviders
|
||||
|
@ -19,8 +20,10 @@ namespace NzbDrone.Core.TransferProviders
|
|||
public ProviderDefinition Definition { get; set; }
|
||||
public abstract ValidationResult Test();
|
||||
|
||||
public abstract string Link { get; }
|
||||
|
||||
public virtual object RequestAction(string action, IDictionary<string, string> query) { return null; }
|
||||
|
||||
public abstract bool IsAvailable(DownloadClientPath item);
|
||||
|
||||
public abstract IVirtualDiskProvider GetFileSystemWrapper(DownloadClientPath item, string tempPath = null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,22 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NzbDrone.Common.Timeline;
|
||||
|
||||
namespace NzbDrone.Core.TransferProviders
|
||||
{
|
||||
public class TransferTask
|
||||
{
|
||||
// TODO: Progress reporting
|
||||
public ITimelineContext Timeline { get; private set; }
|
||||
|
||||
// TODO: Async task or waitable object so Importing can handle.
|
||||
// Async task that is completed once the Transfer has finished or ended in failure. (Do not rely on ProgressReporter for finished detection)
|
||||
public Task CompletionTask { get; private set; }
|
||||
|
||||
public TransferTask(ITimelineContext timeline, Task completionTask)
|
||||
{
|
||||
Timeline = timeline;
|
||||
CompletionTask = completionTask.ContinueWith(t => Timeline.FinishProgress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue