Ejemplo n.º 1
0
        /// <summary>
        /// Copy files one one location to another. This method has the start and destination locations "pinned".
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <param name="files"></param>
        /// <param name="statusUpdate"></param>
        /// <param name="failNow"></param>
        /// <param name="timeout">Minutes of no progress before canceling it</param>
        /// <returns></returns>
        public static async Task <Uri[]> CopyFilesAsync(IPlace source, IPlace destination, Uri[] files, Action <string> statusUpdate = null, Func <bool> failNow = null, int timeout = 60)
        {
            // Simple checks
            var goodFiles = files
                            .ThrowIfNull(() => new ArgumentNullException($"files can't be a null argument"))
                            .Throw(u => u.Scheme != "gridds", u => new UnknownUriSchemeException($"Can only deal with gridds:// uris - found: {u.OriginalString}"));

            if (destination == null)
            {
                throw new ArgumentNullException("Can't have a null destination!");
            }
            if (!(await _places).Contains(destination))
            {
                throw new ArgumentException($"Place {destination.Name} is not on our master list of places!");
            }

            if (source == null)
            {
                throw new ArgumentNullException("Can't have a null source!");
            }
            if (!(await _places).Contains(source))
            {
                throw new ArgumentException($"Place {source.Name} is not on our master list of places!");
            }

            var all_check = await Task.WhenAll(files.Select(async fl => await source.HasFileAsync(fl, statusUpdate, failNow)));

            if (!all_check.All(f => f))
            {
                throw new ArgumentException($"Place {source.Name} does not have all the requested files");
            }

            // Find a route to make them "local", and sort them by the route name (e.g. we can batch the file accesses).
            var routeSources    = new IPlace[] { source };
            var routedFilesList = await Task.WhenAll(goodFiles
                                                     .Select(async u => new RoutedFileInfo {
                r = await FindRouteFromSources((await destination.HasFileAsync(u, statusUpdate, failNow)) ? routeSources.Concat(new IPlace[] { destination }).ToArray() : routeSources, u, p => p == destination, p => p == destination),
                f = u
            }));

            var routedFiles = routedFilesList
                              .GroupBy(info => info.r.Name)
                              .ToArray();

            // To do the files, we need to first fine a routing from wherever they are to the final location.
            var resultUris = await GetListOfRoutedFiles(statusUpdate, failNow, timeout, routedFiles);

            return(resultUris.ToArray());
        }