Example #1
0
        public Task MoveFileAsync(IFileInfo file, AlphaNumericString tag, AlphaNumericString destinationTag, CancellationToken cancellationToken = default)
        {
            var destinationTagPath = GetTagPath(destinationTag);

            if (!Directory.Exists(destinationTagPath))
            {
                Directory.CreateDirectory(destinationTagPath);
            }

            var filePath        = GetFilePath(tag, file);
            var destinationPath = GetFilePath(destinationTag, file);

            File.Move(filePath, destinationPath);

            if (tag != string.Empty)
            {
                var tagPath = GetTagPath(tag);
                if (!Directory.GetDirectories(tagPath).Any() &&
                    !Directory.GetFiles(tagPath).Any())
                {
                    Directory.Delete(tagPath);
                }
            }

            return(Task.CompletedTask);
        }
Example #2
0
        public async Task <bool> CreateFileAsync(IFile file, AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            var tagPath = GetTagPath(tag);

            if (!Directory.Exists(tagPath))
            {
                Directory.CreateDirectory(tagPath);
            }

            var filePath = GetFilePath(tag, file);

            using (var fs = File.Open(filePath, FileMode.Create))
            {
                await file.CopyToAsync(fs, cancellationToken);

                await fs.FlushAsync(cancellationToken);
            }

            return(true);
        }
Example #3
0
        /// <summary>
        /// Creates a prefixed storage of the given <paramref name="storage"/> where
        /// all tags will be prefixed with the given <paramref name="prefix"/>.
        /// </summary>
        /// <param name="storage">The storage to prefix.</param>
        /// <param name="prefix">The non-null or empty tag that should prefix all the tags.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="storage"/> is null.</exception>
        /// <exception cref="ArgumentException">if <paramref name="prefix"/> is null or white space.</exception>
        public PrefixedStorage(IStorage storage, AlphaNumericString prefix)
        {
            if (string.IsNullOrWhiteSpace(prefix))
            {
                throw new ArgumentException("Prefix must not be null or white space.");
            }

            Prefix   = prefix;
            _storage = storage ?? throw new ArgumentNullException(nameof(storage));
        }
Example #4
0
        /// <summary>
        /// Deletes the given <paramref name="tag"/> and all the files associated with the <paramref name="tag"/>.
        /// </summary>
        /// <param name="tag">The tag to remove.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// True if the tag and all its underlying files were successfully deleted, otherwise false if there was
        /// no tag corresponding to the given <paramref name="tag"/>.
        /// </returns>
        public Task <bool> DeleteTagAsync(AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (_files.TryGetValue(tag, out var files))
            {
                files.Clear();
            }
            return(Task.FromResult(_files.Remove(tag)));
        }
Example #5
0
        public Task <IFile> GetFileAsync(IFileInfo fileInfo, AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            var filePath = GetFilePath(tag, fileInfo);

            if (!File.Exists(filePath))
            {
                return(Task.FromResult <IFile>(null));
            }

            var file = new FileSystemFile(filePath);

            return(Task.FromResult <IFile>(file));
        }
Example #6
0
        public IAsyncEnumerable <IFile> GetFiles(AlphaNumericString tag)
        {
            var tagPath = GetTagPath(tag);

            if (!Directory.Exists(tagPath))
            {
                return(AsyncEnumerable.Empty <IFile>());
            }

            return(Directory.GetFiles(tagPath)
                   .Select(path => new FileSystemFile(path))
                   .Cast <IFile>()
                   .ToAsyncEnumerable());
        }
Example #7
0
        /// <summary>
        /// Returns the file associated with the given <paramref name="fileInfo"/> and <paramref name="tag"/>.
        /// If there was no file associated with the <paramref name="fileInfo"/> and <paramref name="tag"/>,
        /// null will be returned, otherwise the file.
        /// </summary>
        /// <param name="fileInfo">The information about the file to retrieve.</param>
        /// <param name="tag">The tag the file is associated with.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// A <see cref="Task{TResult}"/> containing the file associated with the <paramref name="fileInfo"/> and <paramref name="tag"/>.
        /// If no such file exists, the <see cref="Task{TResult}"/> will contain null.
        /// </returns>
        /// <exception cref="ArgumentNullException">If <paramref name="fileInfo"/> is null.</exception>
        public Task <IFile> GetFileAsync(IFileInfo fileInfo, AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (fileInfo == null)
            {
                throw new ArgumentNullException(nameof(fileInfo));
            }

            var file = _files.TryGetValue(tag, out var files)
                ? files.FirstOrDefault(f => f.FileName == fileInfo.FileName)
                : null;

            return(Task.FromResult(file));
        }
Example #8
0
        /// <summary>
        /// Saves the file in memory and associates the file with the given <paramref name="tag"/>.
        /// If a file with the same name exists, the file will be replaced with the given <paramref name="file"/>.
        /// </summary>
        /// <param name="file">The file to save to the memory storage.</param>
        /// <param name="tag">The tag to associate the file with.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        /// <exception cref="ArgumentNullException">If <paramref name="file"/> is null.</exception>
        public async Task <bool> CreateFileAsync(IFile file, AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            if (!_files.TryGetValue(tag, out var files))
            {
                files = new HashSet <IFile>(FileHelpers.FileComparer);
                _files.Add(tag, files);
            }

            if (files.Contains(file))
            {
                files.Remove(file);
            }

            files.Add(await file.ToMemoryAsync());
            return(true);
        }
Example #9
0
        public Task <bool> DeleteFileAsync(IFileInfo file, AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            var filePath = GetFilePath(tag, file);

            if (!File.Exists(filePath))
            {
                return(Task.FromResult(false));
            }

            File.Delete(filePath);

            var tagPath = GetTagPath(tag);

            if (tag != AlphaNumericString.Empty &&
                !Directory.GetFiles(tagPath).Any() &&
                !Directory.GetDirectories(tagPath).Any())
            {
                Directory.Delete(tagPath);
            }

            return(Task.FromResult(true));
        }
Example #10
0
        public Task <bool> DeleteTagAsync(AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            var path = GetTagPath(tag);

            if (!Directory.Exists(path))
            {
                return(Task.FromResult(false));
            }

            var filesInTag = Directory.GetFiles(path);

            foreach (var file in filesInTag)
            {
                File.Delete(file);
            }

            if (tag != AlphaNumericString.Empty)
            {
                Directory.Delete(path);
            }

            return(Task.FromResult(true));
        }
Example #11
0
        /// <summary>
        /// Re-associates the file corresponding to the given <paramref name="file"/> and <paramref name="tag"/>
        /// to the <paramref name="destinationTag"/>.
        /// If the <paramref name="tag"/> is equal to <paramref name="destinationTag"/>, no operation will be performed.
        /// </summary>
        /// <param name="file">The file to associate with the <paramref name="destinationTag"/>.</param>
        /// <param name="tag">The tag the file is currently associated with.</param>
        /// <param name="destinationTag">The tag the file should be associated with.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// A <see cref="Task"/> representing the asynchronous operation.
        /// </returns>
        /// <exception cref="ArgumentNullException">If <paramref name="file"/> is null.</exception>
        public async Task MoveFileAsync(IFileInfo file, AlphaNumericString tag, AlphaNumericString destinationTag, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            if (tag == destinationTag)
            {
                return;
            }

            var existingFile = await GetFileAsync(file, tag, cancellationToken);

            if (existingFile == null)
            {
                return;
            }

            await CreateFileAsync(existingFile, destinationTag, cancellationToken);
            await DeleteFileAsync(existingFile, tag, cancellationToken);
        }
Example #12
0
        /// <summary>
        /// Deletes the file associated with the given <paramref name="file"/> and <paramref name="tag"/>.
        /// If the file doesn't exist, false will be returned, otherwise true.
        /// </summary>
        /// <param name="file">The file to remove.</param>
        /// <param name="tag">The tag the file is located in.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// True if the file was successfully deleted, otherwise false if there was no file associated with the given <paramref name="file"/>
        /// and <paramref name="tag"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">If <paramref name="file"/> is null.</exception>
        public Task <bool> DeleteFileAsync(IFileInfo file, AlphaNumericString tag, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            if (!_files.TryGetValue(tag, out var files))
            {
                return(Task.FromResult(false));
            }

            var existingFile = files.FirstOrDefault(f => f.FileName == file.FileName);

            if (existingFile == null)
            {
                return(Task.FromResult(false));
            }

            files.Remove(existingFile);
            return(Task.FromResult(true));
        }
Example #13
0
 /// <summary>
 /// Returns a collection of zero or more files associated with the given <paramref name="tag"/>.
 /// </summary>
 /// <param name="tag">The tag to retrieve all the associated files from.</param>
 /// <returns>
 /// An <see cref="IAsyncEnumerable{T}"/> containing the zero or more files associated with the
 /// given <paramref name="tag"/>.
 /// </returns>
 public IAsyncEnumerable <IFile> GetFiles(AlphaNumericString tag)
 {
     return(_files.TryGetValue(tag, out var files)
         ? files.ToAsyncEnumerable()
         : AsyncEnumerable <IFile> .Empty);
 }
Example #14
0
 /// <summary>
 /// Re-associates the given <paramref name="file"/>, currently associated with the given <paramref name="tag"/>,
 /// with the <paramref name="destinationTag"/> at the underlying storage, iff the storage has the permission
 /// <see cref="Permission.Move"/>.
 /// </summary>
 /// <param name="file">The file to re-associate with a new tag.</param>
 /// <param name="tag">The tag the file is currently associated with.</param>
 /// <param name="destinationTag">The new tag the file should be associated with.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
 /// <returns>
 /// A <see cref="Task"/> representing the asynchronous operation.
 /// </returns>
 public Task MoveFileAsync(IFileInfo file, AlphaNumericString tag, AlphaNumericString destinationTag, CancellationToken cancellationToken = default)
 {
     ThrowIfNoPermission(Permission.Move);
     return(_storage.MoveFileAsync(file, tag, destinationTag, cancellationToken));
 }
Example #15
0
 /// <summary>
 /// Will always return an empty collection of files.
 /// </summary>
 /// <param name="tag">The tag that doesn't make any difference at all.</param>
 /// <returns>
 /// An <see cref="IAsyncEnumerable{T}"/> of <see cref="IFile"/> that will
 /// always return zero elements.
 /// </returns>
 public IAsyncEnumerable <IFile> GetFiles(AlphaNumericString tag)
 {
     return(AsyncEnumerable <IFile> .Empty);
 }
Example #16
0
 /// <summary>
 /// Will always return null.
 /// </summary>
 /// <param name="fileInfo">The file that will not be retrieved.</param>
 /// <param name="tag">The tag that doesn't make any difference at all.</param>
 /// <param name="cancellationToken">The cancellation token that has nothing to say.</param>
 /// <returns>
 /// A <see cref="Task{TResult}"/> representing the asynchronous operation, that will always contain null.
 /// </returns>
 public Task <IFile> GetFileAsync(IFileInfo fileInfo, AlphaNumericString tag, CancellationToken cancellationToken = default)
 {
     return(Task.FromResult <IFile>(null));
 }
Example #17
0
 /// <summary>
 /// Does not delete any tag at all.
 /// </summary>
 /// <param name="tag">The tag that will not be deleted.</param>
 /// <param name="cancellationToken">The cancellation token that has nothing to say.</param>
 /// <returns>
 /// A <see cref="Task"/> representing the asynchronous operation, that will always
 /// return false.
 /// </returns>
 public Task <bool> DeleteTagAsync(AlphaNumericString tag, CancellationToken cancellationToken = default)
 {
     return(Task.FromResult(false));
 }
Example #18
0
 /// <summary>
 /// Does not delete any file at all.
 /// </summary>
 /// <param name="file">The file to not delete.</param>
 /// <param name="tag">The tag that the doesn't make any difference at all.</param>
 /// <param name="cancellationToken">The cancellation token that has nothing to say.</param>
 /// <returns>
 /// A <see cref="Task"/> representing the asynchronous operation, that will
 /// always contain false.
 /// </returns>
 public Task <bool> DeleteFileAsync(IFileInfo file, AlphaNumericString tag, CancellationToken cancellationToken = default)
 {
     return(Task.FromResult(false));
 }
Example #19
0
 /// <summary>
 /// Will not move any files at all.
 /// </summary>
 /// <param name="file">The file that will not be moved.</param>
 /// <param name="tag">The tag that doesn't make any difference at all.</param>
 /// <param name="destinationTag">The destination tag that doesn't make any difference at all.</param>
 /// <param name="cancellationToken">The cancellation token that has nothing to say.</param>
 /// <returns>
 /// A <see cref="Task"/> representing the asynchronous operation.
 /// </returns>
 public Task MoveFileAsync(IFileInfo file, AlphaNumericString tag, AlphaNumericString destinationTag, CancellationToken cancellationToken = default)
 {
     return(Task.FromResult(0));
 }
Example #20
0
 /// <summary>
 /// Deletes the given <paramref name="file"/>, associated with the given tag, from the underlying storage.
 /// The tag will prefixed with <see cref="Prefix"/> before being queried by the underlying storage.
 /// </summary>
 /// <param name="file">The file to delete from the underlying storage.</param>
 /// <param name="tag">The tag the file is associated with. The tag will be prefixed.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
 /// <returns>
 /// A flag indicating whether the file was successfully deleted from the underlying storage or not.
 /// </returns>
 public Task <bool> DeleteFileAsync(IFileInfo file, AlphaNumericString tag, CancellationToken cancellationToken = default)
 {
     return(_storage.DeleteFileAsync(file, ToPrefixedTag(tag), cancellationToken));
 }
Example #21
0
 /// <summary>
 /// Returns all files associated with the tag prefixed with <see cref="Prefix"/>.
 /// </summary>
 /// <param name="tag">The tag the files should be associated when it is prefixed with <see cref="Prefix"/>.</param>
 /// <returns>
 /// An <see cref="IAsyncEnumerable{T}"/> containing zero or more files associated with the <paramref name="tag"/>
 /// prefixed with <see cref="Prefix"/>.
 /// </returns>
 public IAsyncEnumerable <IFile> GetFiles(AlphaNumericString tag) => _storage.GetFiles(ToPrefixedTag(tag));
Example #22
0
 /// <summary>
 /// Returns all the files associated with the given <paramref name="tag"/> from the underlying storage,
 /// iff the storage has the permission <see cref="Permission.Read"/>.
 /// </summary>
 /// <param name="tag">The tag that the files should be associated with.</param>
 /// <returns>
 /// An <see cref="IAsyncEnumerable{T}"/> containing all the files associated with the given <paramref name="tag"/>.
 /// </returns>
 /// <exception cref="SecurityException">If the storage doesn't have the permission <see cref="Permission.Read"/>.</exception>
 public IAsyncEnumerable <IFile> GetFiles(AlphaNumericString tag)
 {
     ThrowIfNoPermission(Permission.Read);
     return(_storage.GetFiles(tag));
 }
Example #23
0
 /// <summary>
 /// Moves the <paramref name="file"/> associated with the <paramref name="tag"/> when it is prefixed with <see cref="Prefix"/>
 /// to the <paramref name="destinationTag"/> that will be prefixed with <see cref="Prefix"/>.
 /// </summary>
 /// <param name="file">The file to reassociate with a new tag.</param>
 /// <param name="tag">The tag it is currently associated with.</param>
 /// <param name="destinationTag">The new tag the file should be associated with.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
 /// <returns>
 /// A <see cref="Task"/> representing the asynchronous operation.
 /// </returns>
 public Task MoveFileAsync(IFileInfo file, AlphaNumericString tag, AlphaNumericString destinationTag, CancellationToken cancellationToken = default)
 {
     return(_storage.MoveFileAsync(file, ToPrefixedTag(tag), ToPrefixedTag(destinationTag), cancellationToken));
 }
Example #24
0
 private AlphaNumericString ToPrefixedTag(AlphaNumericString tag) => Prefix + tag;
Example #25
0
 private bool IsPrefixedTag(AlphaNumericString tag) => tag.StartsWith(Prefix);
Example #26
0
 /// <summary>
 /// Deletes the given <paramref name="tag"/> from the underlying storage. The <paramref name="tag"/> will
 /// be prefixed with <see cref="Prefix"/> before queried at the underlying storage.
 /// </summary>
 /// <param name="tag">The tag that should be deleted. Will be prefixed.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
 /// <returns>
 /// A flag indicating whether the tag was successfully deleted or not.
 /// </returns>
 public Task <bool> DeleteTagAsync(AlphaNumericString tag, CancellationToken cancellationToken = default)
 {
     return(_storage.DeleteTagAsync(ToPrefixedTag(tag), cancellationToken));
 }
Example #27
0
 private string GetTagPath(AlphaNumericString tag) => Path.Combine(_rootPath, tag);
Example #28
0
 private AlphaNumericString FromPrefixedTag(AlphaNumericString prefixedTag) => prefixedTag.Substring(Prefix.Length);
Example #29
0
 private string GetFilePath(AlphaNumericString tag, IFileInfo file) => Path.Combine(GetTagPath(tag), file.FileName);
Example #30
0
 /// <summary>
 /// Deletes the given <paramref name="tag"/> from the underlying storage, iff the storage
 /// has the permission <see cref="Permission.Delete"/>.
 /// </summary>
 /// <param name="tag">The tag to delete.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
 /// <returns>
 /// A <see cref="Task{TResult}"/> representing the asynchronous operation, containing
 /// a flag indicating whether the tag was successfully deleted or not.
 /// </returns>
 /// <exception cref="SecurityException">If the storage doesn't have the permission <see cref="Permission.Delete"/>.</exception>
 public Task <bool> DeleteTagAsync(AlphaNumericString tag, CancellationToken cancellationToken = default)
 {
     ThrowIfNoPermission(Permission.Delete);
     return(_storage.DeleteTagAsync(tag, cancellationToken));
 }