/// <summary>
        /// <see cref="IDownloader.DownloadModules(NetFileCache, IEnumerable{CkanModule})"/>
        /// </summary>
        public void DownloadModules(
            NetFileCache cache,
            IEnumerable <CkanModule> modules
            )
        {
            var unique_downloads = new Dictionary <Uri, CkanModule>();

            // Walk through all our modules, but only keep the first of each
            // one that has a unique download path.
            foreach (CkanModule module in modules.Where(module => !unique_downloads.ContainsKey(module.download)))
            {
                unique_downloads[module.download] = module;
            }
            this.modules.AddRange(unique_downloads.Values);

            // Schedule us to process our modules on completion.
            onCompleted =
                (_uris, paths, errors) =>
                ModuleDownloadsComplete(cache, _uris, paths, errors);

            // retrieve the expected download size for each mod
            List <KeyValuePair <Uri, long> > downloads_with_size = new List <KeyValuePair <Uri, long> >();

            foreach (var item in unique_downloads)
            {
                downloads_with_size.Add(new KeyValuePair <Uri, long>(item.Key, item.Value.download_size));
            }

            // Start the download!
            Download(downloads_with_size);

            log.Debug("Waiting for downloads to finish...");
            complete_or_canceled.WaitOne();

            var old_download_canceled = download_canceled;

            // Set up the inter-thread comms for next time. Can not be done at the start
            // of the method as the thread could pause on the opening line long enough for
            // a user to cancel.

            download_canceled = false;
            complete_or_canceled.Reset();


            // If the user cancelled our progress, then signal that.
            // This *should* be harmless if we're using the curlsharp downloader,
            // which watches for downloadCanceled all by itself. :)
            if (old_download_canceled)
            {
                // Abort all our traditional downloads, if there are any.
                foreach (var download in downloads.ToList())
                {
                    download.agent.CancelAsync();
                }

                // Abort all our curl downloads, if there are any.
                foreach (var thread in curl_threads.ToList())
                {
                    thread.Abort();
                }

                // Signal to the caller that the user cancelled the download.
                throw new CancelledActionKraken("Download cancelled by user");
            }



            // Check to see if we've had any errors. If so, then release the kraken!
            var exceptions = downloads
                             .Select(x => x.error)
                             .Where(ex => ex != null)
                             .ToList();

            // Let's check if any of these are certificate errors. If so,
            // we'll report that instead, as this is common (and user-fixable)
            // under Linux.
            if (exceptions.Any(ex => ex is WebException &&
                               Regex.IsMatch(ex.Message, "authentication or decryption has failed")))
            {
                throw new MissingCertificateKraken();
            }

            if (exceptions.Count > 0)
            {
                throw new DownloadErrorsKraken(exceptions);
            }

            // Yay! Everything worked!
        }
Exemple #2
0
        /// <summary>
        /// Downloads all the modules specified to the cache.
        /// Even if modules share download URLs, they will only be downloaded once.
        /// Blocks until the download is complete, cancelled, or errored.
        /// </summary>
        public void DownloadModules(
            NetFileCache cache,
            IEnumerable<CkanModule> modules
            )
        {
            var unique_downloads = new Dictionary<Uri, CkanModule>();

            // Walk through all our modules, but only keep the first of each
            // one that has a unique download path.
            foreach (CkanModule module in modules.Where(module => !unique_downloads.ContainsKey(module.download)))
            {
                unique_downloads[module.download] = module;
            }
            this.modules.AddRange(unique_downloads.Values);

            // Schedule us to process our modules on completion.
            onCompleted =
                (_uris, paths, errors) =>
                    ModuleDownloadsComplete(cache, _uris, paths, errors);

            // retrieve the expected download size for each mod
            List<KeyValuePair<Uri, long>> downloads_with_size = new List<KeyValuePair<Uri, long>>();

            foreach(var item in unique_downloads)
            {
                downloads_with_size.Add(new KeyValuePair<Uri, long>(item.Key, item.Value.download_size));
            }

            // Start the download!
            Download(downloads_with_size);

            log.Debug("Waiting for downloads to finish...");
            complete_or_canceled.WaitOne();

            var old_download_canceled = download_canceled;
            // Set up the inter-thread comms for next time. Can not be done at the start
            // of the method as the thread could pause on the opening line long enough for
            // a user to cancel.

            download_canceled = false;
            complete_or_canceled.Reset();

            // If the user cancelled our progress, then signal that.
            // This *should* be harmless if we're using the curlsharp downloader,
            // which watches for downloadCanceled all by itself. :)
            if (old_download_canceled)
            {
                // Abort all our traditional downloads, if there are any.
                foreach (var download in downloads)
                {
                    download.agent.CancelAsync();
                }

                // Abort all our curl downloads, if there are any.
                foreach (var thread in curl_threads)
                {
                    thread.Abort();
                }

                // Signal to the caller that the user cancelled the download.
                throw new CancelledActionKraken("Download cancelled by user");
            }

            // Check to see if we've had any errors. If so, then release the kraken!
            var exceptions = downloads
                .Select(x => x.error)
                .Where(ex => ex != null)
                .ToList();

            // Let's check if any of these are certificate errors. If so,
            // we'll report that instead, as this is common (and user-fixable)
            // under Linux.
            if (exceptions.Any(ex => ex is WebException &&
                Regex.IsMatch(ex.Message, "authentication or decryption has failed")))
            {
                throw new MissingCertificateKraken();
            }

            if (exceptions.Count > 0)
            {
                throw new DownloadErrorsKraken(exceptions);
            }

            // Yay! Everything worked!
        }
Exemple #3
0
        /// <summary>
        /// Downloads all the modules specified to the cache.
        /// Even if modules share download URLs, they will only be downloaded once.
        /// Blocks until the download is complete, cancelled, or errored.
        /// </summary>
        public void DownloadModules(
            NetFileCache cache,
            IEnumerable <CkanModule> modules
            )
        {
            var unique_downloads = new Dictionary <Uri, CkanModule>();

            // Walk through all our modules, but only keep the first of each
            // one that has a unique download path.
            foreach (CkanModule module in modules.Where(module => !unique_downloads.ContainsKey(module.download)))
            {
                unique_downloads[module.download] = module;
            }
            this.modules.AddRange(unique_downloads.Values);
            // Attach our progress report, if requested.
            onCompleted =
                (_uris, paths, errors) =>
                ModuleDownloadsComplete(cache, _uris, paths, errors);

            // Start the download!
            Download(unique_downloads.Keys);

            // The Monitor.Wait function releases a lock, and then waits until it can re-acquire it.
            // Elsewhere, our downloading callback pulses the lock, which causes us to wake up and
            // continue.
            lock (download_complete_lock)
            {
                log.Debug("Waiting for downloads to finish...");
                Monitor.Wait(download_complete_lock);
            }

            // If the user cancelled our progress, then signal that.
            if (downloadCanceled)
            {
                foreach (var download in downloads)
                {
                    download.agent.CancelAsync();
                }

                throw new CancelledActionKraken("Download cancelled by user");
            }

            // Check to see if we've had any errors. If so, then release the kraken!
            List <Exception> exceptions = downloads
                                          .Select(x => x.error)
                                          .Where(ex => ex != null)
                                          .ToList();

            // Let's check if any of these are certificate errors. If so,
            // we'll report that instead, as this is common (and user-fixable)
            // under Linux.
            if (exceptions.Any(ex => ex is WebException &&
                               Regex.IsMatch(ex.Message, "authentication or decryption has failed")))
            {
                throw new MissingCertificateKraken();
            }

            if (exceptions.Count > 0)
            {
                throw new DownloadErrorsKraken(exceptions);
            }

            // Yay! Everything worked!
        }