Ejemplo n.º 1
0
        public async Task <IStorageHistory> CopyItemsAsync(IEnumerable <IStorageItemWithPath> source, IEnumerable <string> destination, IEnumerable <FileNameConflictResolveOptionType> collisions, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || source.Any(x => string.IsNullOrWhiteSpace(x.Path) || x.Path.StartsWith(@"\\?\")) || destination.Any(x => string.IsNullOrWhiteSpace(x) || x.StartsWith(@"\\?\")))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.CopyItemsAsync(source, destination, collisions, progress, errorCode, cancellationToken));
            }

            source      = source.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.Skip).ToList();
            destination = destination.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.Skip).ToList();
            collisions  = collisions.Where(c => c != FileNameConflictResolveOptionType.Skip).ToList();

            var operationID = Guid.NewGuid().ToString();

            using var _ = cancellationToken.Register(CancelOperation, operationID, false);

            EventHandler <Dictionary <string, object> > handler = (s, e) => OnProgressUpdated(s, e, progress);

            connection.RequestReceived += handler;

            var sourceReplace      = source.Where((src, index) => collisions.ElementAt(index) == FileNameConflictResolveOptionType.ReplaceExisting);
            var destinationReplace = destination.Where((src, index) => collisions.ElementAt(index) == FileNameConflictResolveOptionType.ReplaceExisting);
            var sourceRename       = source.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.ReplaceExisting);
            var destinationRename  = destination.Where((src, index) => collisions.ElementAt(index) != FileNameConflictResolveOptionType.ReplaceExisting);

            var result        = (FilesystemResult)true;
            var copiedItems   = new List <string>();
            var copiedSources = new List <string>();

            if (sourceRename.Any())
            {
                var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
                {
                    { "Arguments", "FileOperation" },
                    { "fileop", "CopyItem" },
                    { "operationID", operationID },
                    { "filepath", string.Join('|', sourceRename.Select(s => s.Path)) },
                    { "destpath", string.Join('|', destinationRename) },
                    { "overwrite", false }
                });

                result &= (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                             response.Get("Success", false));
                copiedItems.AddRange(JsonConvert.DeserializeObject <IEnumerable <string> >(response.Get("CopiedItems", "")) ?? Enumerable.Empty <string>());
                copiedSources.AddRange(JsonConvert.DeserializeObject <IEnumerable <string> >(response.Get("CopiedSources", "")) ?? Enumerable.Empty <string>());
            }
            if (sourceReplace.Any())
            {
                var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
                {
                    { "Arguments", "FileOperation" },
                    { "fileop", "CopyItem" },
                    { "operationID", operationID },
                    { "filepath", string.Join('|', sourceReplace.Select(s => s.Path)) },
                    { "destpath", string.Join('|', destinationReplace) },
                    { "overwrite", true }
                });

                result &= (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                             response.Get("Success", false));
                copiedSources.AddRange(JsonConvert.DeserializeObject <IEnumerable <string> >(response.Get("CopiedSources", "")) ?? Enumerable.Empty <string>());
            }

            if (connection != null)
            {
                connection.RequestReceived -= handler;
            }

            if (result)
            {
                progress?.Report(100.0f);
                errorCode?.Report(FileSystemStatusCode.Success);
                if (sourceRename.Any() && copiedItems.Count() == sourceRename.Count())
                {
                    return(new StorageHistory(FileOperationType.Copy, sourceRename,
                                              copiedItems.Select((item, index) => StorageItemHelpers.FromPathAndType(item, sourceRename.ElementAt(index).ItemType))));
                }
                return(null); // Cannot undo overwrite operation
            }
            else
            {
                // Retry failed operations
                var copiedZip = source.Zip(destination, (src, dest) => new { src, dest }).Zip(collisions, (z1, coll) => new { z1.src, z1.dest, coll }).Where(x => !copiedSources.Contains(x.src.Path));
                return(await filesystemOperations.CopyItemsAsync(copiedZip.Select(x => x.src), copiedZip.Select(x => x.dest), copiedZip.Select(x => x.coll), progress, errorCode, cancellationToken));
            }
        }
Ejemplo n.º 2
0
        public async Task <IStorageHistory> CopyItemsAsync(IList <IStorageItemWithPath> source, IList <string> destination, IList <FileNameConflictResolveOptionType> collisions, IProgress <float> progress, IProgress <FileSystemStatusCode> errorCode, CancellationToken cancellationToken)
        {
            var connection = await AppServiceConnectionHelper.Instance;

            if (connection == null || source.Any(x => string.IsNullOrWhiteSpace(x.Path) || x.Path.StartsWith(@"\\?\", StringComparison.Ordinal)) || destination.Any(x => string.IsNullOrWhiteSpace(x) || x.StartsWith(@"\\?\", StringComparison.Ordinal) || FtpHelpers.IsFtpPath(x)))
            {
                // Fallback to builtin file operations
                return(await filesystemOperations.CopyItemsAsync(source, destination, collisions, progress, errorCode, cancellationToken));
            }

            var sourceNoSkip      = source.Zip(collisions, (src, coll) => new { src, coll }).Where(item => item.coll != FileNameConflictResolveOptionType.Skip).Select(item => item.src);
            var destinationNoSkip = destination.Zip(collisions, (src, coll) => new { src, coll }).Where(item => item.coll != FileNameConflictResolveOptionType.Skip).Select(item => item.src);
            var collisionsNoSkip  = collisions.Where(c => c != FileNameConflictResolveOptionType.Skip);

            var operationID = Guid.NewGuid().ToString();

            using var r = cancellationToken.Register(CancelOperation, operationID, false);

            EventHandler <Dictionary <string, object> > handler = (s, e) => OnProgressUpdated(s, e, operationID, progress);

            connection.RequestReceived += handler;

            var sourceReplace      = sourceNoSkip.Zip(collisionsNoSkip, (src, coll) => new { src, coll }).Where(item => item.coll == FileNameConflictResolveOptionType.ReplaceExisting).Select(item => item.src);
            var destinationReplace = destinationNoSkip.Zip(collisionsNoSkip, (src, coll) => new { src, coll }).Where(item => item.coll == FileNameConflictResolveOptionType.ReplaceExisting).Select(item => item.src);
            var sourceRename       = sourceNoSkip.Zip(collisionsNoSkip, (src, coll) => new { src, coll }).Where(item => item.coll != FileNameConflictResolveOptionType.ReplaceExisting).Select(item => item.src);
            var destinationRename  = destinationNoSkip.Zip(collisionsNoSkip, (src, coll) => new { src, coll }).Where(item => item.coll != FileNameConflictResolveOptionType.ReplaceExisting).Select(item => item.src);

            var result     = (FilesystemResult)true;
            var copyResult = new ShellOperationResult();

            if (sourceRename.Any())
            {
                var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
                {
                    { "Arguments", "FileOperation" },
                    { "fileop", "CopyItem" },
                    { "operationID", operationID },
                    { "filepath", string.Join('|', sourceRename.Select(s => s.Path)) },
                    { "destpath", string.Join('|', destinationRename) },
                    { "overwrite", false },
                    { "HWND", NativeWinApiHelper.CoreWindowHandle.ToInt64() }
                });

                result &= (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                             response.Get("Success", false));
                var shellOpResult = JsonConvert.DeserializeObject <ShellOperationResult>(response.Get("Result", ""));
                copyResult.Items.AddRange(shellOpResult?.Items ?? Enumerable.Empty <ShellOperationItemResult>());
            }
            if (sourceReplace.Any())
            {
                var(status, response) = await connection.SendMessageForResponseAsync(new ValueSet()
                {
                    { "Arguments", "FileOperation" },
                    { "fileop", "CopyItem" },
                    { "operationID", operationID },
                    { "filepath", string.Join('|', sourceReplace.Select(s => s.Path)) },
                    { "destpath", string.Join('|', destinationReplace) },
                    { "overwrite", true },
                    { "HWND", NativeWinApiHelper.CoreWindowHandle.ToInt64() }
                });

                result &= (FilesystemResult)(status == AppServiceResponseStatus.Success &&
                                             response.Get("Success", false));
                var shellOpResult = JsonConvert.DeserializeObject <ShellOperationResult>(response.Get("Result", ""));
                copyResult.Items.AddRange(shellOpResult?.Items ?? Enumerable.Empty <ShellOperationItemResult>());
            }

            if (connection != null)
            {
                connection.RequestReceived -= handler;
            }

            result &= (FilesystemResult)copyResult.Items.All(x => x.Succeeded);

            if (result)
            {
                progress?.Report(100.0f);
                errorCode?.Report(FileSystemStatusCode.Success);
                var copiedSources = copyResult.Items.Where(x => x.Succeeded && x.Destination != null && x.Source != x.Destination);
                if (copiedSources.Any())
                {
                    var sourceMatch = await copiedSources.Select(x => sourceRename.SingleOrDefault(s => s.Path == x.Source)).Where(x => x != null).ToListAsync();

                    return(new StorageHistory(FileOperationType.Copy,
                                              sourceMatch,
                                              await copiedSources.Zip(sourceMatch, (rSrc, oSrc) => new { rSrc, oSrc })
                                              .Select(item => StorageHelpers.FromPathAndType(item.rSrc.Destination, item.oSrc.ItemType)).ToListAsync()));
                }
                return(null); // Cannot undo overwrite operation
            }
            else
            {
                // Retry failed operations
                var failedSources = copyResult.Items.Where(x => !x.Succeeded);
                var copyZip       = sourceNoSkip.Zip(destinationNoSkip, (src, dest) => new { src, dest }).Zip(collisionsNoSkip, (z1, coll) => new { z1.src, z1.dest, coll });
                var sourceMatch   = await failedSources.Select(x => copyZip.SingleOrDefault(s => s.src.Path == x.Source)).Where(x => x != null).ToListAsync();

                return(await filesystemOperations.CopyItemsAsync(
                           await sourceMatch.Select(x => x.src).ToListAsync(),
                           await sourceMatch.Select(x => x.dest).ToListAsync(),
                           await sourceMatch.Select(x => x.coll).ToListAsync(), progress, errorCode, cancellationToken));
            }
        }