示例#1
0
        private void OnFileUpdateCompleted(PatchFile File)
        {
            FileUpdateCompleted?.Invoke(File, EventArgs.Empty);

            // Count file updated
            m_PatchFilesCount += 1;
            OnUpdateProgressChanged(m_PatchFilesCount, m_PatchFilesMax);
        }
示例#2
0
        /// <summary>
        /// Check cache from update and synchronize files from patches
        /// </summary>
        private void LoadCache()
        {
            var patchCachePath = Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) + ".patch.cache";

            if (File.Exists(patchCachePath))
            {
                Version cacheVersion = null;
                Dictionary <string, PatchFile> cachePatch = null;
                // Read patch file structure
                using (var reader = new BinaryReader(new FileStream(patchCachePath, FileMode.Open)))
                {
                    cacheVersion = new Version(reader.ReadString());
                    // for each patch file
                    var filesCount = reader.ReadInt32();
                    cachePatch = new Dictionary <string, PatchFile>(filesCount);
                    for (int j = 0; j < filesCount; j++)
                    {
                        var file = new PatchFile(reader.ReadString(), reader.ReadString(), reader.ReadString());
                        cachePatch.Add(file.FullPath, file);
                    }
                }
                // Merge current patches with cache patch to avoid download all the patch again
                foreach (var version in Patches.Keys)
                {
                    if (version == cacheVersion)
                    {
                        var patch = Patches[version];
                        // Create a keys copy to remove from dictionary without issues
                        var paths = new List <string>(patch.Keys);
                        // If file doesn't exist on cache patch, then is already updated
                        foreach (var path in paths)
                        {
                            // Avoid update it again
                            if (!cachePatch.ContainsKey(path))
                            {
                                patch.Remove(path);
                                PatchFiles.Remove(path);
                            }
                        }
                        // Indicate update has been paused
                        IsUpdatePaused = true;
                    }
                }
            }
        }
示例#3
0
 private void OnFileDownloadReady(PatchFile File)
 {
     FileDownloadReady?.Invoke(File, EventArgs.Empty);
 }
示例#4
0
        /// <summary>
        /// Start/continue updating the application
        /// </summary>
        private async Task StartUpdating()
        {
            IsUpdatePaused = false;

            // Check there is files to update
            if (PatchFiles == null || PatchFiles.Count == 0)
            {
                return;
            }

            // Path to check if the executable needs to be updated
            var exePath = Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);

            // Start Downloading files from old patches to new ones
            var versions = new List <Version>(Patches.Keys);

            versions.Sort((a, b) => { return(a.CompareTo(b)); });
            foreach (var version in versions)
            {
                var patch = Patches[version];
                // Create a different instance of keys to remove it without issues
                var paths = new List <string>(patch.Keys);
                // Download and update each file from this version
                for (int i = 0; i < paths.Count; i++)
                {
                    // track updating file
                    var f = m_CurrentFileUpdating = patch[paths[i]];
                    // Check if the file is going to replace this executable
                    bool isExecutable = f.FullPath == exePath;
                    if (isExecutable)
                    {
                        // Check if is not last file to update
                        if (i < (paths.Count - 1))
                        {
                            // Add it again as last one
                            paths.Add(f.FullPath);
                            continue;
                        }
                    }

                    // call event
                    OnFileDownloadReady(f);

                    // track event
                    f.DownloadProgressChanged += OnFileDownloadProgressChanged;

                    // download it
                    await f.StartDownload();

                    // untrack event
                    f.DownloadProgressChanged -= OnFileDownloadProgressChanged;

                    // Check if download has been paused
                    if (f.IsPaused)
                    {
                        break;
                    }

                    // call event
                    var completedEventArgs = OnFileDownloadCompleted(f);

                    // Check if the updating process is going to be handled by manager
                    if (completedEventArgs.CancelUpdate)
                    {
                        await completedEventArgs.ExecuteAction();
                    }
                    else
                    {
                        // Check if is executable
                        if (isExecutable)
                        {
                            // update it slightly different (delete super old, move old and forget then move new)
                            var thrashPath = Path.Combine(DownloadingPath, exePath + ".old");
                            await Task.Run(() =>
                            {
                                if (File.Exists(thrashPath))
                                {
                                    File.Delete(thrashPath);
                                }
                                File.Move(exePath, thrashPath);
                                File.Move(f.DownloadPath, exePath);
                            });
                        }
                        else
                        {
                            // update it
                            await f.Update();
                        }
                    }

                    // Check if is the executable being updated
                    if (isExecutable)
                    {
                        // delete cache
                        DeleteCache();
                    }
                    else
                    {
                        // Create backup to continue the update on restart
                        SaveCache(version, patch);
                    }

                    // remove it from tracking
                    patch.Remove(f.FullPath);
                    PatchFiles.Remove(f.FullPath);

                    // call event
                    OnFileUpdateCompleted(f);

                    // Start calling a events to restart the application
                    if (isExecutable)
                    {
                        // call event
                        OnPatchCompleted(version);

                        // Check if this is the last file from everything for update
                        if (PatchFiles.Count == 0)
                        {
                            // call event
                            OnUpdateCompleted();
                        }

                        // Restart application
                        OnApplicationRestart();

                        // Execute new executable and exit from this one
                        System.Diagnostics.Process.Start(exePath);
                        Environment.Exit(0);
                    }
                }

                // Stop tracking as updating
                m_CurrentFileUpdating = null;

                // Check if update has been paused
                if (IsUpdatePaused)
                {
                    break;
                }

                // call event
                OnPatchCompleted(version);
            }

            // Patch finished
            if (PatchFiles.Count == 0)
            {
                // delete cache
                DeleteCache();
                // call event
                OnUpdateCompleted();
            }
        }
示例#5
0
        /// <summary>
        /// Initialize the pachting files to be downloaded and updated
        /// </summary>
        /// <param name="Patch">Patch to prepare</param>
        /// <param name="SupportOldVersion">Check if your application supports versions that are not found on patch</param>
        public async Task InitializeUpdate(PatchVersion Patch, bool SupportOldVersion = false)
        {
            // Set SSL/TLS is correctly being set
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol  = SecurityProtocolType.Tls12;

            // Create web client to check patch files
            using (WebClient web = new WebClient())
            {
                // Patch to download
                var patchRequiredUrl = Patch.PatchUrl;
                // Avoid repeating files
                PatchFiles = new Dictionary <string, PatchFile>();
                // Collect all files that will be used for patching
                Patches = new Dictionary <Version, Dictionary <string, PatchFile> >();

                // Create downloading folder and hide it from user
                if (!Directory.Exists(DownloadingPath))
                {
                    DirectoryInfo dirInfo = Directory.CreateDirectory(DownloadingPath);
                    dirInfo.Attributes = FileAttributes.Directory | FileAttributes.Hidden;
                }

                // Start reading web patches
                Version patchVersion = null;
                do
                {
                    // Download, read and convert JSON to class
                    var patchInfo = JsonDeserializer <PatchInfo>(await web.DownloadStringTaskAsync(patchRequiredUrl));

                    // If the version is the same as my current version, stop it
                    patchVersion = new Version(patchInfo.Version);
                    if (patchVersion == CurrentVersion)
                    {
                        break;
                    }

                    // Create version patch if doesn't exist
                    if (!Patches.TryGetValue(patchVersion, out Dictionary <string, PatchFile> patch))
                    {
                        patch = new Dictionary <string, PatchFile>();
                        Patches[patchVersion] = patch;
                    }
                    // Collects non repeated files
                    foreach (string file in patchInfo.Files)
                    {
                        if (!PatchFiles.ContainsKey(file))
                        {
                            // Add file to this patch
                            var patchFile = new PatchFile(file, patchInfo.Host + file, Path.Combine(DownloadingPath, PatchFiles.Count.ToString().PadLeft(8, '0')));
                            patch.Add(file, patchFile);
                            PatchFiles.Add(file, patchFile);
                        }
                    }
                    // Remove it if this patch doesn't have files
                    if (patch.Count == 0)
                    {
                        Patches.Remove(patchVersion);
                    }

                    // Collect files from patch dependencies
                    patchRequiredUrl = patchInfo.PatchRequiredUrl;
                } while (!string.IsNullOrEmpty(patchRequiredUrl));

                // Check if the update version is matching with app
                if (!SupportOldVersion && patchVersion > CurrentVersion)
                {
                    throw new ApplicationException("The version of your application is too old to be updated.");
                }

                // Check if there is cache to synchronize
                LoadCache();

                m_PatchFilesMax   = PatchFiles.Count;
                m_PatchFilesCount = 0;
            }
        }