using MediaBrowser.Common.Extensions; using System; using System.Collections.Concurrent; using System.IO; using System.Threading.Tasks; namespace MediaBrowser.Common.IO { /// /// This is a wrapper for storing large numbers of files within a directory on a file system. /// Simply pass a filename into GetResourcePath and it will return a full path location of where the file should be stored. /// public class FileSystemRepository : IDisposable { /// /// Contains the list of subfolders under the main directory /// The directory entry is created when the item is first added to the dictionary /// private readonly ConcurrentDictionary _subFolderPaths = new ConcurrentDictionary(); /// /// The _file locks /// private readonly NamedLock _fileLocks = new NamedLock(); /// /// Gets or sets the path. /// /// The path. protected string Path { get; set; } /// /// Initializes a new instance of the class. /// /// The path. /// public FileSystemRepository(string path) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(); } Path = path; Initialize(); } /// /// Initializes this instance. /// protected void Initialize() { if (!Directory.Exists(Path)) { Directory.CreateDirectory(Path); } } /// /// Gets the full path of where a resource should be stored within the repository /// /// Name of the unique. /// The file extension. /// System.String. /// public string GetResourcePath(string uniqueName, string fileExtension) { if (string.IsNullOrEmpty(uniqueName)) { throw new ArgumentNullException(); } if (string.IsNullOrEmpty(fileExtension)) { throw new ArgumentNullException(); } var filename = uniqueName.GetMD5() + fileExtension; return GetResourcePath(filename); } /// /// Gets the full path of where a file should be stored within the repository /// /// The filename. /// System.String. /// public string GetResourcePath(string filename) { if (string.IsNullOrEmpty(filename)) { throw new ArgumentNullException(); } return GetInternalResourcePath(filename); } /// /// Takes a filename and returns the full path of where it should be stored /// /// The filename. /// System.String. private string GetInternalResourcePath(string filename) { var prefix = filename.Substring(0, 1); var folder = _subFolderPaths.GetOrAdd(prefix, GetCachePath); return System.IO.Path.Combine(folder, filename); } /// /// Creates a subfolder under the image cache directory and returns the full path /// /// The prefix. /// System.String. private string GetCachePath(string prefix) { var path = System.IO.Path.Combine(Path, prefix); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } return path; } /// /// Determines if a resource is present in the repository /// /// Name of the unique. /// The file extension. /// true if the specified unique name contains resource; otherwise, false. public bool ContainsResource(string uniqueName, string fileExtension) { return ContainsFilePath(GetResourcePath(uniqueName, fileExtension)); } /// /// Determines if a file with a given name is present in the repository /// /// The filename. /// true if the specified filename contains filename; otherwise, false. /// public bool ContainsFilename(string filename) { if (string.IsNullOrEmpty(filename)) { throw new ArgumentNullException(); } return ContainsFilePath(GetInternalResourcePath(filename)); } /// /// Determines if a file is present in the repository /// /// The path. /// true if [contains file path] [the specified path]; otherwise, false. /// public bool ContainsFilePath(string path) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(); } return File.Exists(path); } /// /// Waits for lock. /// /// The resource path. public Task WaitForLockAsync(string resourcePath) { return _fileLocks.WaitAsync(resourcePath); } /// /// Releases the lock. /// /// The resource path. public void ReleaseLock(string resourcePath) { _fileLocks.Release(resourcePath); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Dispose(true); } /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { if (dispose) { _fileLocks.Dispose(); } } } }