// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // The Update Service // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.Services { using System; using System.IO; using System.Net; using System.Security.Cryptography; using System.Text; using System.Threading; using HandBrake.ApplicationServices.Utilities; using HandBrake.ApplicationServices.Interop; using HandBrakeWPF.Model; using HandBrakeWPF.Services.Interfaces; using AppcastReader = HandBrakeWPF.Utilities.AppcastReader; /// /// The Update Service /// public class UpdateService : IUpdateService { #region Constants and Fields /// /// Backing field for the update service /// private readonly IUserSettingService userSettingService; #endregion #region Constructors and Destructors /// /// Initializes a new instance of the class. /// /// /// The user setting service. /// public UpdateService(IUserSettingService userSettingService) { this.userSettingService = userSettingService; } #endregion #region Public Methods /// /// Perform an update check at application start, but only daily, weekly or monthly depending on the users settings. /// /// /// The callback. /// public void PerformStartupUpdateCheck(Action callback) { // Make sure it's running on the calling thread if (this.userSettingService.GetUserSetting(UserSettingConstants.UpdateStatus)) { DateTime lastUpdateCheck = this.userSettingService.GetUserSetting(UserSettingConstants.LastUpdateCheckDate); int checkFrequency = this.userSettingService.GetUserSetting(UserSettingConstants.DaysBetweenUpdateCheck) == 0 ? 7 : 30; if (DateTime.Now.Subtract(lastUpdateCheck).TotalDays > checkFrequency) { this.userSettingService.SetUserSetting(UserSettingConstants.LastUpdateCheckDate, DateTime.Now); this.CheckForUpdates(callback); } } } /// /// Check for Updates /// /// /// The callback. /// public void CheckForUpdates(Action callback) { ThreadPool.QueueUserWorkItem( delegate { try { string url = VersionHelper.Is64Bit() || Environment.Is64BitOperatingSystem ? Constants.Appcast64 : Constants.Appcast32; if (VersionHelper.IsNightly()) { url = VersionHelper.Is64Bit() || Environment.Is64BitOperatingSystem ? Constants.AppcastUnstable64 : Constants.AppcastUnstable32; } var currentBuild = HandBrakeUtils.Build; // Initialize variables WebRequest request = WebRequest.Create(url); WebResponse response = request.GetResponse(); var reader = new AppcastReader(); // Get the data, convert it to a string, and parse it into the AppcastReader reader.GetUpdateInfo(new StreamReader(response.GetResponseStream()).ReadToEnd()); // Further parse the information string build = reader.Build; int latest = int.Parse(build); int current = currentBuild; var info2 = new UpdateCheckInformation { NewVersionAvailable = latest > current, DescriptionUrl = reader.DescriptionUrl, DownloadFile = reader.DownloadFile, Build = reader.Build, Version = reader.Version, ExpectedSHA1Hash = reader.Hash }; callback(info2); } catch (Exception exc) { callback(new UpdateCheckInformation { NewVersionAvailable = false, Error = exc }); } }); } /// /// Download the update file. /// /// /// The url. /// /// /// The expected Sha 1 Hash. /// /// /// The complete. /// /// /// The progress. /// public void DownloadFile(string url, string expectedSha1Hash, Action completed, Action progress) { ThreadPool.QueueUserWorkItem( delegate { string tempPath = Path.Combine(Path.GetTempPath(), "handbrake-setup.exe"); WebClient wcDownload = new WebClient(); try { if (File.Exists(tempPath)) File.Delete(tempPath); HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url); webRequest.Credentials = CredentialCache.DefaultCredentials; HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); long fileSize = webResponse.ContentLength; Stream responceStream = wcDownload.OpenRead(url); Stream localStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None); int bytesSize; byte[] downBuffer = new byte[2048]; while ((bytesSize = responceStream.Read(downBuffer, 0, downBuffer.Length)) > 0) { localStream.Write(downBuffer, 0, bytesSize); progress(new DownloadStatus { BytesRead = localStream.Length, TotalBytes = fileSize}); } responceStream.Close(); localStream.Close(); completed( GetSHA1(tempPath) != expectedSha1Hash ? new DownloadStatus { WasSuccessful = false, Message = "Download Failed. SHA1 Checksum Failed. Please visit the website to download this update." } : new DownloadStatus { WasSuccessful = true, Message = "Download Complete." }); } catch (Exception exc) { progress(new DownloadStatus { WasSuccessful = false, Exception = exc, Message = "Download Failed. Please visit the website to download this update." }); } }); } /// /// The get sh a 1. /// /// /// The file name. /// /// /// The . /// public static String GetSHA1(String fileName) { FileStream file = new FileStream(fileName, FileMode.Open); SHA1 sha1 = new SHA1CryptoServiceProvider(); byte[] retVal = sha1.ComputeHash(file); file.Close(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < retVal.Length; i++) { sb.Append(retVal[i].ToString("x2")); } return sb.ToString(); } #endregion } }