using System.Linq; using System; using System.Collections.Generic; using System.IO; using NLog; using NzbDrone.Common; using NzbDrone.Common.Disk; using NzbDrone.Common.Instrumentation; using NzbDrone.Core.Configuration; using NzbDrone.Core.Tv; using NzbDrone.Common.Cache; using NzbDrone.Core.Download; using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.RemotePathMappings { public interface IRemotePathMappingService { List All(); RemotePathMapping Add(RemotePathMapping mapping); void Remove(int id); RemotePathMapping Get(int id); RemotePathMapping Update(RemotePathMapping mapping); OsPath RemapRemoteToLocal(String host, OsPath remotePath); OsPath RemapLocalToRemote(String host, OsPath localPath); // TODO: Remove around January 2015. Used to migrate legacy Local Category Path settings. void MigrateLocalCategoryPath(Int32 downloadClientId, IProviderConfig newSettings, String host, OsPath remotePath, OsPath localPath); } public class RemotePathMappingService : IRemotePathMappingService { // TODO: Remove DownloadClientRepository reference around January 2015. Used to migrate legacy Local Category Path settings. private readonly IDownloadClientRepository _downloadClientRepository; private readonly IRemotePathMappingRepository _remotePathMappingRepository; private readonly IDiskProvider _diskProvider; private readonly Logger _logger; private readonly ICached> _cache; public RemotePathMappingService(IDownloadClientRepository downloadClientRepository, IRemotePathMappingRepository remotePathMappingRepository, IDiskProvider diskProvider, ICacheManager cacheManager, Logger logger) { _downloadClientRepository = downloadClientRepository; _remotePathMappingRepository = remotePathMappingRepository; _diskProvider = diskProvider; _logger = logger; _cache = cacheManager.GetCache>(GetType()); } public List All() { return _cache.Get("all", () => _remotePathMappingRepository.All().ToList(), TimeSpan.FromSeconds(10)); } public RemotePathMapping Add(RemotePathMapping mapping) { mapping.LocalPath = new OsPath(mapping.LocalPath).AsDirectory().FullPath; mapping.RemotePath = new OsPath(mapping.RemotePath).AsDirectory().FullPath; var all = All(); ValidateMapping(all, mapping); var result = _remotePathMappingRepository.Insert(mapping); _cache.Clear(); return result; } public void Remove(int id) { _remotePathMappingRepository.Delete(id); _cache.Clear(); } public RemotePathMapping Get(int id) { return _remotePathMappingRepository.Get(id); } public RemotePathMapping Update(RemotePathMapping mapping) { var existing = All().Where(v => v.Id != mapping.Id).ToList(); ValidateMapping(existing, mapping); var result = _remotePathMappingRepository.Update(mapping); _cache.Clear(); return result; } private void ValidateMapping(List existing, RemotePathMapping mapping) { if (mapping.Host.IsNullOrWhiteSpace()) { throw new ArgumentException("Invalid Host"); } var remotePath = new OsPath(mapping.RemotePath); var localPath = new OsPath(mapping.LocalPath); if (remotePath.IsEmpty) { throw new ArgumentException("Invalid RemotePath"); } if (localPath.IsEmpty || !localPath.IsRooted) { throw new ArgumentException("Invalid LocalPath"); } if (!_diskProvider.FolderExists(localPath.FullPath)) { throw new DirectoryNotFoundException("Can't add mount point directory that doesn't exist."); } if (existing.Exists(r => r.Host == mapping.Host && r.RemotePath == mapping.RemotePath)) { throw new InvalidOperationException("RemotePath already mounted."); } } public OsPath RemapRemoteToLocal(String host, OsPath remotePath) { if (remotePath.IsEmpty) { return remotePath; } foreach (var mapping in All()) { if (host == mapping.Host && new OsPath(mapping.RemotePath).Contains(remotePath)) { var localPath = new OsPath(mapping.LocalPath) + (remotePath - new OsPath(mapping.RemotePath)); return localPath; } } return remotePath; } public OsPath RemapLocalToRemote(String host, OsPath localPath) { if (localPath.IsEmpty) { return localPath; } foreach (var mapping in All()) { if (host == mapping.Host && new OsPath(mapping.LocalPath).Contains(localPath)) { var remotePath = new OsPath(mapping.RemotePath) + (localPath - new OsPath(mapping.LocalPath)); return remotePath; } } return localPath; } // TODO: Remove around January 2015. Used to migrate legacy Local Category Path settings. public void MigrateLocalCategoryPath(Int32 downloadClientId, IProviderConfig newSettings, String host, OsPath remotePath, OsPath localPath) { _logger.Debug("Migrating local category path for Host {0}/{1} to {2}", host, remotePath, localPath); var existingMappings = All().Where(v => v.Host == host).ToList(); if (!existingMappings.Any(v => new OsPath(v.LocalPath) == localPath && new OsPath(v.RemotePath) == remotePath)) { Add(new RemotePathMapping { Host = host, RemotePath = remotePath.FullPath, LocalPath = localPath.FullPath }); } var downloadClient = _downloadClientRepository.Get(downloadClientId); downloadClient.Settings = newSettings; _downloadClientRepository.Update(downloadClient); } } }