/// <summary> /// Instructs the AutoUpdateDownloader to query for the latest version available /// </summary> /// <param name="progressViewer">The progress viewer by which progress should be displayed</param> /// <param name="options">The options that affect this downloader</param> /// <param name="productToUpdate">The product descriptor for the product that should be updated</param> /// <param name="updateAvailable">The download descriptor that describes the download that could potentially occur</param> /// <returns></returns> public virtual bool QueryLatestVersion( IProgressViewer progressViewer, AutoUpdateOptions options, AutoUpdateProductDescriptor productToUpdate, out AutoUpdateDownloadDescriptor updateAvailable) { updateAvailable = null; return(false); }
/// <summary> /// Instructs the AutoUpdateDownloader to query for the latest version available /// </summary> /// <param name="progressViewer">The progress viewer by which progress should be displayed</param> /// <param name="options">The options that affect this downloader</param> /// <param name="productToUpdate">The product descriptor for the product that should be updated</param> /// <param name="updateAvailable">The download descriptor that describes the download that could potentially occur</param> /// <returns></returns> public override bool QueryLatestVersion(IProgressViewer progressViewer, AutoUpdateOptions options, AutoUpdateProductDescriptor productToUpdate, out AutoUpdateDownloadDescriptor updateAvailable) { updateAvailable = null; try { // create a manual web service proxy based on the url specified in the options Debug.WriteLine(string.Format("Creating a web service proxy to the following url.\n\tThe web service url is '{0}'.", options.WebServiceUrl), MY_TRACE_CATEGORY); AutoUpdateWebServiceProxy service = new AutoUpdateWebServiceProxy(options.WebServiceUrl); // use the web service to query for updates Debug.WriteLine(string.Format("Querying the web service for the latest version of '{0}'.\n\tThe current product's version is '{1}'.\n\tThe current product's id is '{2}'.\n\tThe web service url is '{3}'.", productToUpdate.Name, productToUpdate.Version.ToString(), productToUpdate.Id, options.WebServiceUrl), MY_TRACE_CATEGORY); XmlNode node = service.QueryLatestVersion(productToUpdate.Name, productToUpdate.Version.ToString(), productToUpdate.Id); // if the service returned no results, then there is no update availabe if (node == null) { // bail out Debug.WriteLine(string.Format("No updates are available from the web service at '{0}' for this product.", options.WebServiceUrl), MY_TRACE_CATEGORY); return false; } // otherwise create a reader and try and read the xml from the xml node returned from the web service XmlAutoUpdateManifestReader reader = new XmlAutoUpdateManifestReader(node); // using the reader we can recreate the manifeset from the xml AutoUpdateManifest manifest = reader.Read(); /* * now create a download descriptor that says, yes we have found an update. * we are capable of downloading it, according to these options. * the autoupdate manager will decide which downloader to use to download the update * */ updateAvailable = new AutoUpdateDownloadDescriptor(manifest, this, options); // just to let everyone know that there is a version available Debug.WriteLine(string.Format("Version '{0}' of '{1}' is available for download.\n\tThe download url is '{2}'.\n\tThe size of the download is {3}.", updateAvailable.Manifest.Product.Version.ToString(), updateAvailable.Manifest.Product.Name, updateAvailable.Manifest.UrlOfUpdate, this.FormatFileLengthForDisplay(updateAvailable.Manifest.SizeOfUpdate)), MY_TRACE_CATEGORY); // we've successfully queried for the latest version of the product to update return true; } catch(ThreadAbortException) { } catch (WebException ex) { Debug.WriteLine(ex.Message, MY_TRACE_CATEGORY); } return false; }
/// <summary> /// Bubble sorts the elements in the descriptor array using their product verion (The newest version will be at element 0). /// </summary> /// <param name="updates"></param> /// <returns></returns> public static AutoUpdateDownloadDescriptor[] Sort(AutoUpdateDownloadDescriptor[] updates) { // front to back - 1 for (int i = 0; i < updates.Length - 1; i++) { // front + 1 to back for (int j = i + 1; j < updates.Length; j++) { if (updates[i].Manifest.Product.Version < updates[j].Manifest.Product.Version) { // swap i with j, where i=1 and j=2 AutoUpdateDownloadDescriptor update = updates[j]; updates[j] = updates[i]; updates[i] = update; } } } return(updates); }
/// <summary> /// Adjusts the url where the .update can be found, using the product descriptor and the alternate download path /// </summary> /// <remarks> /// By default the url probably points to some web url. When the update is copied to the alternate download path /// we want the download to occur from that path, so the url in the manifest must be manipulated to point the download /// to the update in the alternate path. /// </remarks> /// <param name="options"></param> /// <param name="downloadDescriptor"></param> public virtual void AdjustUrlOfUpdateInManifest(AutoUpdateOptions options, AutoUpdateDownloadDescriptor downloadDescriptor) { /* * we're supposed to be adjusting the the url where the update can be downloaded * to point to the alternate path * where ideally the manifest file will reside alongside the update * * the problem is that the manifest file contains a url to where the update was originally downloaded * most likely some web server somewhere, which after the manifest is copied to some network file share * we won't want to use, more likely in an effort to keep the downloaders from going over the web * we'll try and tweak the url to just be the unc path of the download as it resides next to the * manifest in the alternate download path * * */ try { // if there's no alternate path, don't worry about adjusting anything // as nothing is going to be copied anyways if (options.AlternatePath == null || options.AlternatePath == string.Empty) // if there return; // redirect the url of the update to the alternate location downloadDescriptor.Manifest.UrlOfUpdate = string.Format("{0}\\{1}\\{1}-{2}.Update", options.AlternatePath, downloadDescriptor.Manifest.Product.Name, downloadDescriptor.Manifest.Product.Version.ToString()); } catch(ThreadAbortException) { } }
/// <summary> /// Creates a copy of the manifest file in the alternate path /// </summary> /// <param name="downloadDescriptor"></param> public virtual void CreateCopyOfManifestInAlternatePath(IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) { try { // if the alternate path is not set, then we don't have to do this if (downloadDescriptor.Options.AlternatePath == null || downloadDescriptor.Options.AlternatePath == string.Empty) return; // format a path to the product's alternate path string altPath = Path.Combine(downloadDescriptor.Options.AlternatePath, downloadDescriptor.Manifest.Product.Name); // if the path doesn't exist, just bail, we don't create alternate paths bool folderExists = Directory.Exists(altPath); Debug.WriteLine(string.Format("Confirming the product's 'Alternate Download Path' folder.\n\tThe folder '{0}' {1}.", altPath, (folderExists ? "already exists" : "does not exist")), MY_TRACE_CATEGORY); if (!folderExists) { Debug.WriteLine(string.Format("Creating the product's 'Alternate Download Path' folder at '{0}'.", altPath), MY_TRACE_CATEGORY); Directory.CreateDirectory(altPath); } // format a path to the file in the alternate path string dstPath = Path.Combine(altPath, string.Format("{0}-{1}.manifest", downloadDescriptor.Manifest.Product.Name, downloadDescriptor.Manifest.Product.Version.ToString())); bool fileExists = File.Exists(dstPath); Debug.WriteLine(string.Format("Preparing to copy the manifest to the product's 'Alternate Download Path' folder.\n\tThe file '{0}' {1}.", dstPath, (fileExists ? "already exists" : "does not exist")), MY_TRACE_CATEGORY); // otherwise write the manifest to the alternate path ProgressViewer.SetExtendedDescription(progressViewer, "Creating a backup copy of the manifest file."); Debug.WriteLine(string.Format("Copying the manifest to '{0}'.", dstPath), MY_TRACE_CATEGORY); XmlAutoUpdateManifestWriter.Write(downloadDescriptor.Manifest, dstPath, System.Text.Encoding.UTF8); } catch(ThreadAbortException) { } catch(Exception ex) { Debug.WriteLine(ex); } }
/// <summary> /// Decrypts the .update file to a .zip file using the name of the .update file as a base in the same directory as the .update file /// </summary> /// <param name="progressViewer"></param> /// <param name="updateFilename"></param> /// <param name="zipFilename"></param> /// <returns></returns> protected virtual bool DecryptToZip(IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor, out string zipFilename) { zipFilename = null; try { ProgressViewer.SetExtendedDescription(progressViewer, "Parsing update..."); // save the path to the update string updateFilename = downloadDescriptor.DownloadedPath; // format the .zip file zipFilename = Path.Combine(Path.GetDirectoryName(updateFilename), Path.GetFileName(updateFilename).Replace(Path.GetExtension(updateFilename), null) + ".zip"); /* * Dev Note: Versions 1 & 2 encrypted the zip files. Version 3 in Carbon will not. * Just copy the update to the zip location. **/ File.Copy(updateFilename, zipFilename); //// it is rijndael encrypted //RijndaelEncryptionEngine ee = new RijndaelEncryptionEngine(); //// decrypt the .update file to a .zip file //Debug.WriteLine(string.Format("Converting the update into an archive.\n\tThe archive will exist at '{0}'.", zipFilename), MY_TRACE_CATEGORY); //ee.Decrypt(updateFilename, zipFilename); return true; } catch(ThreadAbortException) { } return false; }
/// <summary> /// Unzips the .zip file to a directory of it's own using the name of the .zip file as a base /// </summary> /// <param name="progressViewer"></param> /// <param name="zipFilename"></param> /// <returns></returns> protected virtual bool Unzip(IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor, string zipFilename) { ZipInputStream zipStream = null; FileStream fs = null; string newVersionPath = null; try { // calculate the rootname //string rootName = Path.GetFileName(zipFilename).Replace(Path.GetExtension(zipFilename), null); //// the text to remove includes the name of the product and a dash //string prependedTextToRemove = string.Format("{0}-", downloadDescriptor.Manifest.Product.Name); //// remove that and we're left with a version //rootName = rootName.Replace(prependedTextToRemove, null); // extract here string rootPath = Path.GetDirectoryName(zipFilename); // the destination where the files will be unzipped for the new version //newVersionPath = Path.Combine(rootPath, rootName); newVersionPath = Path.Combine(rootPath, downloadDescriptor.Manifest.Product.Version.ToString()); // make sure the directory where the new version will be extracted exists bool folderExists = Directory.Exists(newVersionPath); Debug.WriteLine(string.Format("Confirming the new version's path.\n\tThe folder '{0}' {1}.", newVersionPath, (folderExists ? "already exists" : "does not exist")), MY_TRACE_CATEGORY); if (!folderExists) { Debug.WriteLine(string.Format("Creating the new verion's folder '{0}'.", newVersionPath), MY_TRACE_CATEGORY); Directory.CreateDirectory(newVersionPath); } // try and find the postbuildevent.bat file string postBuildFile = Path.Combine(rootPath, "PostBuildEvent.bat"); // open the zip file using a zip input stream Debug.WriteLine(string.Format("Opening the archive '{0}' for reading.", zipFilename), MY_TRACE_CATEGORY); zipStream = new ZipInputStream(File.OpenRead(zipFilename)); // ready each zip entry ZipEntry zipEntry; while ((zipEntry = zipStream.GetNextEntry()) != null) { try { string zipEntryFilename = Path.Combine(rootPath, zipEntry.Name); zipEntryFilename = zipEntryFilename.Replace("/", "\\"); // trace the entry to where it is going Debug.WriteLine(string.Format("Extracting '{0}' to '{1}'.", zipEntry.Name, zipEntryFilename), MY_TRACE_CATEGORY); if (zipEntry.IsDirectory) { Debug.WriteLine(string.Format("Creating the folder '{0}'.", zipEntryFilename), MY_TRACE_CATEGORY); Directory.CreateDirectory(zipEntryFilename); } else { ProgressViewer.SetExtendedDescription(progressViewer, "Extracting " + zipEntry.Name + "..."); // make sure the directory exists FileInfo fi = new FileInfo(zipEntryFilename); DirectoryInfo di = fi.Directory; if (!Directory.Exists(di.FullName)) Directory.CreateDirectory(di.FullName); fi = null; di = null; // create each file fs = File.Create(zipEntryFilename); int size = 2048; byte[] data = new byte[size]; while (true) { size = zipStream.Read(data, 0, data.Length); if (size > 0) fs.Write(data, 0, size); else break; } // close the extracted file fs.Close(); fs = null; } } catch (Exception ex) { Debug.WriteLine(ex); } } // close the zip stream zipStream.Close(); RunFileIfFound(progressViewer, postBuildFile); return true; } catch (ThreadAbortException) { try { // make sure the streams are closed if (zipStream != null) zipStream.Close(); if (fs != null) fs.Close(); // delete the root folder of the new install upon cancellation Directory.Delete(newVersionPath, true); } catch (Exception ex) { Debug.WriteLine(ex); } } catch (Exception ex) { Debug.WriteLine(ex); } finally { // make sure the streams are closed if (zipStream != null) zipStream.Close(); if (fs != null) fs.Close(); } return false; }
/// <summary> /// Sorts the available downloads and returns the newest download descriptor as the one that should be downloaded /// </summary> /// <param name="updates"></param> /// <returns></returns> protected virtual AutoUpdateDownloadDescriptor SelectTheDownloadWithTheNewestUpdate(AutoUpdateDownloadDescriptor[] downloadDescriptors) { try { // if there are no downloads if (downloadDescriptors == null) // then simply say so return null; if (downloadDescriptors.Length > 0) { // otherwise, sort them into descending order with the newest version at index zero. downloadDescriptors = AutoUpdateDownloadDescriptor.Sort(downloadDescriptors); // simply return the first one return downloadDescriptors[0]; } } catch(ThreadAbortException) { } // otherwise don't return null; }
/// <summary> /// Installs the .update file specified by decrypting it and then unziping the contents to a new versioned directory (ie. 1.0.0.1) /// </summary> /// <param name="progressViewer"></param> /// <param name="updateFilename"></param> /// <returns></returns> protected virtual bool InstallUpdate(IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) { string zipFilename = null; try { Debug.WriteLine(string.Format("Preparing to install update from '{0}'.", downloadDescriptor.DownloadedPath), MY_TRACE_CATEGORY); // decrypt the .update file first if (!this.DecryptToZip(progressViewer, downloadDescriptor, out zipFilename)) return false; // then unzip the .zip file if (this.Unzip(progressViewer, downloadDescriptor, zipFilename)) { // delete the zip file File.Delete(zipFilename); return true; } } catch(ThreadAbortException) { try { // delete the zip file File.Delete(zipFilename); } catch(Exception ex) { Debug.WriteLine(ex); } } return false; }
/// <summary> /// Initializes a new instance of the AutoUpdateDownloadDescriptorEventArgs class /// </summary> /// <param name="downloadDescriptor">The descriptor that describes the download.</param> public AutoUpdateDownloadDescriptorEventArgs(AutoUpdateDownloadDescriptor downloadDescriptor) : base() { _descriptor = downloadDescriptor; }
/// <summary> /// Initializes a new instance of the AutoUpdateManagerWithDownloadDescriptorCancelEventArgs class. /// </summary> /// <param name="manager">The AutoUpdateManager that is handling the update.</param> /// <param name="progressViewer">The IProgressViewer that can be used to display progress about the update.</param> /// <param name="downloadDescriptor">The AutoUpdateDownloadDescriptor that describes teh update available.</param> /// <param name="cancel">A flag that indicates whether the event should be cancelled or not.</param> public AutoUpdateManagerWithDownloadDescriptorCancelEventArgs(AutoUpdateManager manager, IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor, bool cancel) : base(manager, progressViewer, downloadDescriptor) { _cancel = cancel; }
/// <summary> /// Instructs the AutoUpdateDownloader to cleanup after an install /// </summary> /// <param name="progressViewer">The progress viewer by which progress should be displayed</param> /// <param name="downloadDescriptor">The download descriptor that describes the download that occurred and was installed</param> public virtual bool FinalizeInstallation( IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) { return(true); }
/// <summary> /// Instructs the AutoUpdateDownloader to query for the latest version available /// </summary> /// <param name="progressViewer">The progress viewer by which progress should be displayed</param> /// <param name="options">The options that affect this downloader</param> /// <param name="productToUpdate">The product descriptor for the product that should be updated</param> /// <param name="updateAvailable">The download descriptor that describes the download that could potentially occur</param> /// <returns></returns> public virtual bool QueryLatestVersion( IProgressViewer progressViewer, AutoUpdateOptions options, AutoUpdateProductDescriptor productToUpdate, out AutoUpdateDownloadDescriptor updateAvailable) { updateAvailable = null; return false; }
/// <summary> /// Instructs the AutoUpdateDownloader to download the update specified by the update descriptor /// </summary> /// <param name="progressViewer">The progress viewer by which progress should be displayed</param> /// <param name="downloadDescriptor">The download descriptor that describes the download that should occur</param> /// <returns></returns> public virtual bool Download( IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) { FileStream localStream = null; Stream remoteStream = null; string myTraceCategory = string.Format("'{0}'", this.GetType().Name); try { // set the progress to zero for the start this.SetDownloadProgress(progressViewer, 0, downloadDescriptor.Manifest.SizeOfUpdate); // format the downloaded path where the .update file will be when the download is finished downloadDescriptor.DownloadedPath = Path.Combine(downloadDescriptor.Options.DownloadPath, Path.GetFileName(downloadDescriptor.Manifest.UrlOfUpdate)); Debug.WriteLine(string.Format("Preparing to download update.\n\tThe update will be downloaded from '{0}'.\n\tThe update will be downloaded to '{1}'.", downloadDescriptor.Manifest.UrlOfUpdate, downloadDescriptor.DownloadedPath), myTraceCategory); // if the url where this update is supposed to be located is not set, just quit as there isn't anything else we can do if (downloadDescriptor.Manifest.UrlOfUpdate == null || downloadDescriptor.Manifest.UrlOfUpdate == string.Empty) { return(false); } // create a new web client to download the file WebClient wc = new WebClient(); // open a remote stream to the download Debug.WriteLine(string.Format("Preparing to download update.\n\tOpening stream to the remote url '{0}'.", downloadDescriptor.Manifest.UrlOfUpdate), myTraceCategory); remoteStream = wc.OpenRead(downloadDescriptor.Manifest.UrlOfUpdate); // open a local file stream where the update will be downloaded Debug.WriteLine(string.Format("Preparing to download update.\n\tOpening stream to the local url '{0}'.", downloadDescriptor.DownloadedPath), myTraceCategory); localStream = new FileStream(downloadDescriptor.DownloadedPath, FileMode.Create, FileAccess.Write, FileShare.None); // if successfull we'll receive the data in segments if (remoteStream != null) { long bytesDownloaded = 0; while (true) { // figure out how many bytes we have to download long bytesToReceive = downloadDescriptor.Manifest.SizeOfUpdate - bytesDownloaded; // correct it if it's more than the segment size if (bytesToReceive > _segmentSize) { bytesToReceive = (long)_segmentSize; } byte[] segment = new byte[bytesToReceive]; // read a segment off the socket int bytesReceived = remoteStream.Read(segment, 0, (int)bytesToReceive); // bail if nothing read if (bytesReceived == 0) { break; } // if we received anything if (bytesReceived > 0) { // write it to the update file localStream.Write(segment, 0, bytesReceived); // update the position bytesDownloaded += bytesReceived; } // update the progress viewer this.SetDownloadProgress(progressViewer, bytesDownloaded, downloadDescriptor.Manifest.SizeOfUpdate); } } Debug.WriteLine(string.Format("The update was successfully downloaded to '{0}'.", downloadDescriptor.DownloadedPath), myTraceCategory); return(true); } catch (ThreadAbortException) { } catch (Exception ex) { try { if (localStream != null) { localStream.Close(); } if (remoteStream != null) { remoteStream.Close(); } } catch (Exception) { } try { // something broke, make sure we delete the .update file File.Delete(downloadDescriptor.DownloadedPath); } catch (Exception) { } throw ex; } finally { /* * make sure the streams are closed * */ try { if (localStream != null) { localStream.Close(); } if (remoteStream != null) { remoteStream.Close(); } } catch {} try { } catch {} } // if it's made it this far something went wrong return(false); }
/// <summary> /// Initializes a new instance of the AutoUpdateDownloadDescriptorCancelEventArgs class. /// </summary> /// <param name="cancel">A flag that indicates whether the event should be cancelled.</param> /// <param name="updateDescriptor">The AutoUpdateDownloadDescriptor that is the context of the event.</param> public AutoUpdateDownloadDescriptorCancelEventArgs(bool cancel, AutoUpdateDownloadDescriptor downloadDescriptor) : base(downloadDescriptor) { _cancel = cancel; }
/// <summary> /// Bubble sorts the elements in the descriptor array using their product verion (The newest version will be at element 0). /// </summary> /// <param name="updates"></param> /// <returns></returns> public static AutoUpdateDownloadDescriptor[] Sort(AutoUpdateDownloadDescriptor[] updates) { // front to back - 1 for(int i = 0; i < updates.Length - 1; i++) { // front + 1 to back for(int j = i + 1; j < updates.Length; j++) { if (updates[i].Manifest.Product.Version < updates[j].Manifest.Product.Version) { // swap i with j, where i=1 and j=2 AutoUpdateDownloadDescriptor update = updates[j]; updates[j] = updates[i]; updates[i] = update; } } } return updates; }
/// <summary> /// Creates a copy of the update file in the alternate path /// </summary> /// <param name="progressViewer"></param> /// <param name="updateFilename"></param> /// <returns></returns> public virtual void CreateCopyOfUpdateInAlternatePath(IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) { try { // if the alternate path is not set, then we don't have to do this if (downloadDescriptor.Options.AlternatePath == null || downloadDescriptor.Options.AlternatePath == string.Empty) return; // take the alternate path string altPath = Path.Combine(downloadDescriptor.Options.AlternatePath, downloadDescriptor.Manifest.Product.Name); // see if the folder exists bool folderExists = Directory.Exists(altPath); Debug.WriteLine(string.Format("Confirming the product's 'Alternate Download Path' folder.\n\tThe folder '{0}' {1}.", altPath, (folderExists ? "already exists" : "does not exist")), MY_TRACE_CATEGORY); if (!folderExists) { Debug.WriteLine(string.Format("Creating the product's 'Alternate Download Path' folder at '{0}'.", altPath), MY_TRACE_CATEGORY); Directory.CreateDirectory(altPath); } // format the backup filename from the alternate path, and the url where the update string dstPath = Path.Combine(altPath, Path.GetFileName(downloadDescriptor.Manifest.UrlOfUpdate)); // see if the file already exists bool fileExists = File.Exists(dstPath); Debug.WriteLine(string.Format("Preparing to copy the update to the product's 'Alternate Download Path' folder.\n\tThe file '{0}' {1}.", dstPath, (fileExists ? "already exists" : "does not exist")), MY_TRACE_CATEGORY); // copy the .update we downloaded to the backup location in the alternate path directory ProgressViewer.SetExtendedDescription(progressViewer, "Creating a backup copy of the update file."); Debug.WriteLine(string.Format("Copying the update to '{0}'.", dstPath), MY_TRACE_CATEGORY); File.Copy(downloadDescriptor.DownloadedPath, dstPath, false); } catch(ThreadAbortException) { } catch(Exception ex) { Debug.WriteLine(ex); } }
/// <summary> /// Instructs the AutoUpdateDownloader to download the update specified by the update descriptor /// </summary> /// <param name="progressViewer">The progress viewer by which progress should be displayed</param> /// <param name="downloadDescriptor">The download descriptor that describes the download that should occur</param> /// <returns></returns> public virtual bool Download( IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) { FileStream localStream = null; Stream remoteStream = null; string myTraceCategory = string.Format("'{0}'", this.GetType().Name); try { // set the progress to zero for the start this.SetDownloadProgress(progressViewer, 0, downloadDescriptor.Manifest.SizeOfUpdate); // format the downloaded path where the .update file will be when the download is finished downloadDescriptor.DownloadedPath = Path.Combine(downloadDescriptor.Options.DownloadPath, Path.GetFileName(downloadDescriptor.Manifest.UrlOfUpdate)); Debug.WriteLine(string.Format("Preparing to download update.\n\tThe update will be downloaded from '{0}'.\n\tThe update will be downloaded to '{1}'.", downloadDescriptor.Manifest.UrlOfUpdate, downloadDescriptor.DownloadedPath), myTraceCategory); // if the url where this update is supposed to be located is not set, just quit as there isn't anything else we can do if (downloadDescriptor.Manifest.UrlOfUpdate == null || downloadDescriptor.Manifest.UrlOfUpdate == string.Empty) return false; // create a new web client to download the file WebClient wc = new WebClient(); // open a remote stream to the download Debug.WriteLine(string.Format("Preparing to download update.\n\tOpening stream to the remote url '{0}'.", downloadDescriptor.Manifest.UrlOfUpdate), myTraceCategory); remoteStream = wc.OpenRead(downloadDescriptor.Manifest.UrlOfUpdate); // open a local file stream where the update will be downloaded Debug.WriteLine(string.Format("Preparing to download update.\n\tOpening stream to the local url '{0}'.", downloadDescriptor.DownloadedPath), myTraceCategory); localStream = new FileStream(downloadDescriptor.DownloadedPath, FileMode.Create, FileAccess.Write, FileShare.None); // if successfull we'll receive the data in segments if (remoteStream != null) { long bytesDownloaded = 0; while (true) { // figure out how many bytes we have to download long bytesToReceive = downloadDescriptor.Manifest.SizeOfUpdate - bytesDownloaded; // correct it if it's more than the segment size if (bytesToReceive > _segmentSize) bytesToReceive = (long)_segmentSize; byte[] segment = new byte[bytesToReceive]; // read a segment off the socket int bytesReceived = remoteStream.Read(segment, 0, (int)bytesToReceive); // bail if nothing read if (bytesReceived == 0) break; // if we received anything if (bytesReceived > 0) { // write it to the update file localStream.Write(segment, 0, bytesReceived); // update the position bytesDownloaded += bytesReceived; } // update the progress viewer this.SetDownloadProgress(progressViewer, bytesDownloaded, downloadDescriptor.Manifest.SizeOfUpdate); } } Debug.WriteLine(string.Format("The update was successfully downloaded to '{0}'.", downloadDescriptor.DownloadedPath), myTraceCategory); return true; } catch(ThreadAbortException) { } catch(Exception ex) { try { if (localStream != null) localStream.Close(); if (remoteStream != null) remoteStream.Close(); } catch(Exception) { } try { // something broke, make sure we delete the .update file File.Delete(downloadDescriptor.DownloadedPath); } catch(Exception) { } throw ex; } finally { /* * make sure the streams are closed * */ try { if (localStream != null) localStream.Close(); if (remoteStream != null) remoteStream.Close(); } catch {} try { } catch {} } // if it's made it this far something went wrong return false; }
/// <summary> /// Initializes a new instance of the AutoUpdateManagerWithDownloadDescriptorEventArgs class. /// </summary> /// <param name="manager">The AutoUpdateManager that is handling the update.</param> /// <param name="progressViewer">The IProgressViewer that can be used to display progress about the update.</param> /// <param name="downloadDescriptor">The AutoUpdateDownloadDescriptor that describes teh update available.</param> public AutoUpdateManagerWithDownloadDescriptorEventArgs(AutoUpdateManager manager, IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) : base(manager, progressViewer) { _downloadDescriptor = downloadDescriptor; }
/// <summary> /// Instructs the AutoUpdateDownloader to cleanup after an install /// </summary> /// <param name="progressViewer">The progress viewer by which progress should be displayed</param> /// <param name="downloadDescriptor">The download descriptor that describes the download that occurred and was installed</param> public virtual bool FinalizeInstallation( IProgressViewer progressViewer, AutoUpdateDownloadDescriptor downloadDescriptor) { return true; }