/// <summary>If there already a package in the download directory, this function gets the present downloaded package. If anything is invalid (wrong format of the version file, /// wrong hash sum), the return value is <c>Null</c>.</summary> /// <param name="fs">Stream to read the version info from. This must be the opened stream of the VersionInfo.txt file in the download directory.</param> /// <param name="storagePath">Path to the directory that stores the downloaded package.</param> /// <param name="packageFile">On successfull return, the opened <see cref="FileStream"/> of the package file is provided here. You are responsible for closing the stream!</param> /// <returns>The info for the already present package in the download directory. If anything is invalid, the return value is null.</returns> public static PackageInfo GetPresentDownloadedPackage(Stream fs, string storagePath, out FileStream packageFile) { PackageInfo packageInfo = null; packageFile = null; try { var packageInfos = PackageInfo.FromStream(fs); packageInfo = PackageInfo.GetHighestVersion(packageInfos); // test, if the file exists and has the right Hash var fileInfo = new FileInfo(Path.Combine(storagePath, GetPackageFileName(packageInfo.Version))); if (!fileInfo.Exists) { return(null); } // test for the appropriate length if (fileInfo.Length != packageInfo.FileLength) { return(null); } packageFile = new FileStream(Path.Combine(storagePath, GetPackageFileName(packageInfo.Version)), FileMode.Open, FileAccess.Read, FileShare.Read); var hashProvider = new System.Security.Cryptography.SHA1Managed(); var hash = hashProvider.ComputeHash(packageFile); if (GetHashAsString(hash) != packageInfo.Hash) { throw new InvalidOperationException("Hash of downloaded package is not valid"); } return(packageInfo); } catch (Exception) { } return(null); }
/// <summary>Runs the <see cref="Downloader"/>.</summary> /// <remarks> /// The download is done in steps: /// <para>Firstly, the appropriate version file in the application data directory is locked, /// so that no other program can use it, until this program ends.</para> /// <para>Then, the version file is downloaded from the remote location.</para> /// <para>If there is already a valid version file in the download directory, /// and the version obtained from the remote version file is equal to the version obtained from the version file in the download directory, /// then the package was already downloaded before. Then we only check that the package file is also present and that it has the appropriate hash sum.</para> /// <para>Else, if the version obtained from the remote version file is higher than the program's current version, /// we download the package file from the remote location.</para> /// </remarks> public void Run() { if (!Directory.Exists(_storagePath)) { Directory.CreateDirectory(_storagePath); SetDownloadDirectoryAccessRights(_storagePath); } var versionFileFullName = Path.Combine(_storagePath, PackageInfo.VersionFileName); using (var fs = new FileStream(versionFileFullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { fs.Seek(0, SeekOrigin.Begin); var alreadyDownloadedVersion = PackageInfo.GetPresentDownloadedPackage(fs, _storagePath); fs.Seek(0, SeekOrigin.Begin); using (var webClient = new System.Net.WebClient()) { Console.Write("Starting to download version file ..."); var versionData = webClient.DownloadData(_downloadURL + PackageInfo.VersionFileName); Console.WriteLine(" ok! ({0} bytes downloaded)", versionData.Length); // we leave the file open, thus no other process can access it var parsedVersions = PackageInfo.FromStream(new MemoryStream(versionData)); fs.Write(versionData, 0, versionData.Length); fs.Flush(); // write the new version to disc in order to change the write date // from all parsed versions, choose that one that matches the requirements var parsedVersion = PackageInfo.GetHighestVersion(parsedVersions); if (null != parsedVersion) { Console.WriteLine("The remote package version is: {0}", parsedVersion.Version); } else { Console.WriteLine("This computer does not match the requirements of any package. The version file contains {0} packages.", parsedVersions.Length); return; } if (Comparer <Version> .Default.Compare(parsedVersion.Version, _currentVersion) > 0) // if the remote version is higher than the currently installed Altaxo version { Console.Write("Cleaning download directory ..."); CleanDirectory(versionFileFullName); // Clean old downloaded files from the directory Console.WriteLine(" ok!"); var packageUrl = _downloadURL + PackageInfo.GetPackageFileName(parsedVersion.Version); var packageFileName = Path.Combine(_storagePath, PackageInfo.GetPackageFileName(parsedVersion.Version)); Console.WriteLine("Starting download of package file ..."); webClient.DownloadProgressChanged += EhDownloadOfPackageFileProgressChanged; webClient.DownloadFileCompleted += EhDownloadOfPackageFileCompleted; _isDownloadOfPackageCompleted = false; webClient.DownloadFileAsync(new Uri(packageUrl), packageFileName);// download the package asynchronously to get progress messages for (; !_isDownloadOfPackageCompleted;) { System.Threading.Thread.Sleep(250); } webClient.DownloadProgressChanged -= EhDownloadOfPackageFileProgressChanged; webClient.DownloadFileCompleted -= EhDownloadOfPackageFileCompleted; Console.WriteLine("Download finished!"); // make at least the test for the right length var fileInfo = new FileInfo(packageFileName); if (fileInfo.Length != parsedVersion.FileLength) { Console.WriteLine("Downloaded file length ({0}) differs from length in VersionInfo.txt {1}, thus the downloaded file will be deleted!", fileInfo.Length, parsedVersion.FileLength); fileInfo.Delete(); } else { Console.WriteLine("Test file length of downloaded package file ... ok!"); } } } } }