/// <summary> /// Prepares a BITS job adding the files and creating the required folders. /// </summary> /// <param name="backgroundCopyJob">The BITS job information.</param> /// <param name="task">The DownloadTask instace.</param> private static void PrepareJob(IBackgroundCopyJob backgroundCopyJob, DownloadTask task) { Guid jobID; backgroundCopyJob.GetId(out jobID); task.JobId = jobID; DownloadFile sourceFile = task.DownloadItem.File; string src = sourceFile.Source; // to defend against config errors, check to see if the path given is UNC; // if so, throw immediately there's a misconfiguration. Paths to BITS must be HTTP or HTTPS if (FileHelper.IsUncPath(src)) { Exception ex = new DownloaderException("Download location must be HTTP or HTTPS URL"); Logger.Error(ex); throw ex; } //TODO: how about duplicate filenames? string dest = Path.Combine(task.DownloadFilesBase, sourceFile.LocalName); if (!Directory.Exists(Path.GetDirectoryName(dest))) { Directory.CreateDirectory(Path.GetDirectoryName(dest)); } // add this file to the job backgroundCopyJob.AddFile(src, dest); }
/// <summary> /// Waits for the download to complete, for the synchronous usage of the downloader. /// </summary> /// <param name="backgroundCopyJob">The job instance reference.</param> /// <param name="maxWaitTime">The maximum wait time.</param> /// <param name="task">The updater task instance.</param> private void WaitForDownload(DownloadTask task, IBackgroundCopyJob backgroundCopyJob, TimeSpan maxWaitTime) { bool isCompleted = false; bool isSuccessful = false; try { Guid jobID; backgroundCopyJob.GetId(out jobID); // set endtime to current tickcount + allowable # milliseconds to wait for job double endTime = Environment.TickCount + maxWaitTime.TotalMilliseconds; while (!isCompleted) { BG_JOB_STATE state; backgroundCopyJob.GetState(out state); switch (state) { case BG_JOB_STATE.BG_JOB_STATE_SUSPENDED: { OnDownloadStarted(new TaskEventArgs(task)); backgroundCopyJob.Resume(); break; } case BG_JOB_STATE.BG_JOB_STATE_ERROR: { // use utility to: // a) get error info // b) report it // c) cancel and remove copy job OnJobError(task, backgroundCopyJob, null, null); // complete loop, but DON'T say it's successful isCompleted = true; break; } case BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR: { // NOTE: during debugging + test, transient errors resulted in complete job failure about 90% // of the time. Therefore we treat transients just like full errors, and CANCEL the job // use utility to manage error etc. OnJobError(task, backgroundCopyJob, null, null); // stop the loop, set completed to true but not successful isCompleted = true; break; } case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRING: { OnJobModification(task, backgroundCopyJob); break; } case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED: { OnJobTransferred(task, backgroundCopyJob); isCompleted = true; isSuccessful = true; break; } default: break; } if (isCompleted) { break; } if (endTime < Environment.TickCount) { var ex = new DownloaderException("Download attempt timed out"); OnJobError(task, backgroundCopyJob, null, ex); break; } // Avoid 100% CPU utilisation with too tight a loop, let download happen. Thread.Sleep(TimeToWaitDuringSynchronousDownload); } if (!isSuccessful) { // create message + error, package it, publish var ex = new DownloaderException(String.Format("Download attempt for {0} failed", task.DownloadItem.ItemId)); OnJobError(task, backgroundCopyJob, null, ex); } } catch (ThreadInterruptedException tie) { // if interrupted, clean up job OnJobError(task, backgroundCopyJob, null, tie); } }
protected override void When() { Exception = new DownloaderException("TESTMESSAGE", InnerException); }