public override async Task <bool> CheckForUpdates()
        {
            if (ClientProfile == null)
            {
                return(false);
            }
            if (ServerProfile == null)
            {
                return(false);
            }

            // Should never hit, earlier logic shouldn't even call the function
            if (!ServerProfile.IsOfficial)
            {
                return(false);
            }

            if (ClientProfile.Localization != ClientLocalization.Japan &&
                ClientProfile.Localization != ClientLocalization.JapanHangame)
            {
                return(false);
            }

            PatcherContext.SetPatcherState(true);

            PatcherContext.UpdateMainProgress("Checking for updates...", "", 0, true, true);

            _officialPatchInfo = OfficialPatchInfo.Parse(MabiVersion.Versions
                                                         .Find(version => version.Name == ClientProfile.Localization).PatchUrl);

            if (int.TryParse(_officialPatchInfo["main_version"], out var versionConverted))
            {
                _remoteVersion = versionConverted;
            }

            if (_currentVersion == _remoteVersion)
            {
                PatcherContext.SetPatcherState(false);
                PatcherContext.UpdateMainProgress("", "", 0, false, false);
                return(false);
            }

            try
            {
                await Task.Run(() => _patchSequence = FindPatchSequence());
            }
            catch (PatchSequenceNotFoundException ex)
            {
                Log.Exception(ex);
                PatcherContext.SetPatcherState(false);
                PatcherContext.UpdateMainProgress("", "", 0, false, false);
                return(false);
            }

            PatcherContext.SetPatcherState(false);
            PatcherContext.UpdateMainProgress("", "", 0, false, false);
            return(true);
        }
Beispiel #2
0
        private async Task <List <FileDownloadInfo> > GetFileDownloadInfo()
        {
            double entries = ((ICollection)PatchData.files).Count;

            PatcherContext.UpdateMainProgress(Properties.Resources.ParsingManifest, $"0/{entries}", 0, false, true);
            var fileDownloadInfos = new List <FileDownloadInfo>();

            await Task.Delay(1);

            int entry = 0;

            // Decode filepaths into new collection
            foreach (var file in PatchData["files"])
            {
                entry++;
                PatcherContext.UpdateMainProgress(Properties.Resources.ParsingManifest, $"{entry}/{entries}", entry / entries * 100, false, true);

                var isDirectory     = false;
                var filename        = file.Name;
                var decodedFilename = DecodeFilename(filename);

                // Nexon does not intend for this file to be downloaded or this may be some other specification
                if (file.Value["objects"].Count == 0)
                {
                    Log.Info(Properties.Resources.FileWithNoObjectsIgnored, decodedFilename);
                    continue;
                }

                if (file.Value["objects"][0] == "__DIR__")
                {
                    isDirectory = true;
                }

                var fileDownloadInfo = new FileDownloadInfo(decodedFilename, file.Value["fsize"].Value,
                                                            isDirectory ? FileInfoType.Directory : FileInfoType.File);

                fileDownloadInfo.SetModifiedTimeDateTime(file.Value["mtime"].Value);

                if (isDirectory)
                {
                    continue;
                }

                for (var i = 0; i < file.Value["objects"].Count; i++)
                {
                    var filePartInfo =
                        new FilePartInfo(file.Value["objects"][i].Value, decodedFilename, file.Value["objects_fsize"][i].Value, i);
                    fileDownloadInfo.FileParts.Add(filePartInfo);
                }

                fileDownloadInfos.Add(fileDownloadInfo);
            }

            return(fileDownloadInfos);
        }
Beispiel #3
0
        public override async Task <bool> RepairInstall()
        {
            var shouldUpdate = await CheckForUpdatesInternal(-1, true);

            if (shouldUpdate)
            {
                return(await ApplyUpdates());
            }
            PatcherContext.SetPatcherState(false);
            PatcherContext.UpdateMainProgress("", "", 0, false, false);
            return(true);
        }
            public void Finish()
            {
                double count     = _downloadWrappers.Count;
                int    completed = 0;

                _patcherContext.UpdateMainProgress(Properties.Resources.FinalizingFiles, $"{completed}/{count}", 0, false, true);

                var actions = _downloadWrappers.Values.Select(downloadWrapper => (Action)(() =>
                {
                    downloadWrapper.Finish();
                    Interlocked.Increment(ref completed);
                    _patcherContext.UpdateMainProgress(Properties.Resources.FinalizingFiles, $"{completed}/{count}", completed / count * 100, false, true);
                }))
                              .ToList();

                _downloadWrappers.Clear();

                Parallel.Invoke(new ParallelOptions {
                    MaxDegreeOfParallelism = 10
                }, actions.ToArray());
            }
Beispiel #5
0
        public override async Task <bool> CheckForUpdates()
        {
            if (ValidateAction(true))
            {
                return(false);
            }

            PatcherContext.UpdateMainProgress(Properties.Resources.Initialize, "", 0, true, true);

            var completed = "true";

            PatcherContext.SetPatcherState(true);

            PatcherContext.UpdateMainProgress(Properties.Resources.CheckingForUpdates, "", 0, true, true);

            if (!NexonApi.Instance.IsAccessTokenValid(ClientProfile.Guid))
            {
                completed = "";
                PatcherContext.RequestUserLogin(() => completed = "true", () => completed = "false");
            }

            while (completed == "")
            {
                await Task.Delay(100);
            }

            if (completed == "false")
            {
                PatcherContext.SetPatcherState(false);
                PatcherContext.UpdateMainProgress("", "", 0, false, false);
                return(false);
            }

            var result = await CheckForUpdatesInternal(ReadVersion());

            PatcherContext.SetPatcherState(false);
            PatcherContext.UpdateMainProgress("", "", 0, false, false);

            return(result);
        }
Beispiel #6
0
        private async Task GetManifestJson(int version)
        {
            if (version == -1)
            {
                PatcherContext.UpdateMainProgress(Properties.Resources.GettingLatestVersion, "", 0, true, true);
                _version = version = await NexonApi.Instance.GetLatestVersion();
            }

            PatcherContext.UpdateMainProgress(Properties.Resources.DownloadingManifest, "", 0, true, true);
            // Get Manifest String
            var manifestHashString = await NexonApi.Instance.GetManifestHashString();

            // Download Manifest
            var buffer = DownloadManifestBuffer(manifestHashString);

            PatcherContext.UpdateMainProgress(Properties.Resources.DecompressingManifest, "", 0, true, true);

            // Decompress Manifest and Convert to Object
            var manifestContent = ZlibStream.UncompressString(buffer);
            var data            = JsonConvert.DeserializeObject <dynamic>(manifestContent);

            PatchData = data;
        }
Beispiel #7
0
        public override async Task <bool> ApplyUpdates()
        {
            if (ValidateAction())
            {
                return(false);
            }

            PatcherContext.SetPatcherState(true);
            PatcherContext.ShowSession();
            PatcherContext.UpdateMainProgress(Properties.Resources.ApplyingUpdates, "", 0, true, true);

            var patchDownloader = new PatchDownloader(Patches, ClientProfile, PatcherContext);

            bool result = false;

            try
            {
                await Task.Run(() => patchDownloader.Prepare());

                result = await Task.Run(() => patchDownloader.Patch());

                await Task.Run(() => patchDownloader.Cleanup());
            }
            catch (Exception ex)
            {
                Log.Exception(ex, "Failed to patch!");
            }
            finally
            {
                PatcherContext.UpdateMainProgress(result ? Properties.Resources.PatchComplete : Properties.Resources.PatchFailed);

                PatcherContext.SetPatcherState(false);
                PatcherContext.HideSession();
            }

            return(result);
        }
Beispiel #8
0
        private void GetPatchList(bool overrideSettings = false)
        {
            double entries = FileDownloadInfos.Count;

            PatcherContext.UpdateMainProgress(Properties.Resources.CheckingFiles, $"0/{entries}", 0, false, true);

            var entry = 0;

            foreach (var fileDownloadInfo in FileDownloadInfos)
            {
                entry++;
                PatcherContext.UpdateMainProgress(Properties.Resources.CheckingFiles, $"{entry}/{entries}",
                                                  entry / entries * 100, false,
                                                  true);

                var filePath = fileDownloadInfo.FileName;

                if (!overrideSettings)
                {
                    if (filePath.StartsWith("package\\") &&
                        PatchSettingsManager.Instance.PatcherSettings.IgnorePackageFolder &&
                        !GetIsNewPackFile(filePath))
                    {
                        continue;
                    }
                }

                if (PatchIgnore.IgnoredFiles.Contains(filePath))
                {
                    Log.Info($"File: '{filePath}' in ignore list, file will not be patched!");
                    continue;
                }

                if (fileDownloadInfo.FileInfoType == FileInfoType.Directory)
                {
                    if (Directory.Exists(fileDownloadInfo.FileName))
                    {
                        continue;
                    }

                    Patches.Add(new Patch(fileDownloadInfo, PatchReason.DoesNotExist));
                    continue;
                }

                var  modified       = false;
                var  fileExists     = true;
                var  actualModified = new DateTime();
                var  correctSize    = true;
                long length         = 0;

                if (File.Exists(filePath))
                {
                    length         = new FileInfo(filePath).Length;
                    actualModified = File.GetLastWriteTime(filePath);
                    if (actualModified != fileDownloadInfo.LastModifiedDateTime)
                    {
                        modified = true;
                    }
                    else if (length != fileDownloadInfo.FileSize)
                    {
                        correctSize = false;
                    }
                }
                else
                {
                    fileExists = false;
                }

                if (!correctSize)
                {
                    var patch = new Patch(fileDownloadInfo, PatchReason.SizeNotMatch);
                    Patches.Add(patch);
                    Log.Info(Properties.Resources.PatchRequiredForSize, filePath,
                             patch.PatchReason.LocalizedPatchReason(), fileDownloadInfo.FileSize, length);
                    continue;
                }

                if (!fileExists)
                {
                    var patch = new Patch(fileDownloadInfo, PatchReason.DoesNotExist);
                    Patches.Add(patch);
                    Log.Info(Properties.Resources.PatchRequiredFor, filePath, patch.PatchReason.LocalizedPatchReason());
                    continue;
                }

                if (!modified)
                {
                    continue;
                }

                if (actualModified > fileDownloadInfo.LastModifiedDateTime)
                {
                    var patch = new Patch(fileDownloadInfo, PatchReason.Modified);
                    Patches.Add(patch);
                    Log.Info(Properties.Resources.PatchRequiredFor, filePath, patch.PatchReason.LocalizedPatchReason());
                }
                else
                {
                    var patch = new Patch(fileDownloadInfo);
                    Patches.Add(patch);
                    Log.Info(Properties.Resources.PatchRequiredFor, filePath, patch.PatchReason.LocalizedPatchReason());
                }
            }
        }
Beispiel #9
0
        public List <PatchFileInfo> Verify()
        {
            Log.Info(Properties.Resources.BeginningFileVerification);
            _patcherContext.UpdateMainProgress(Properties.Resources.BeginningFileVerification,
                                               isIndeterminate: true,
                                               isProgressbarVisible: true);

            var list = new List <PatchFileInfo>();

            using (var md5 = MD5.Create())
            {
                foreach (var patchFileInfo in PatchInfo.Files)
                {
                    try
                    {
                        // TODO: Global Cancellation token
                        CancellationToken.None.ThrowIfCancellationRequested();
                    }
                    catch
                    {
                        break;
                    }

                    _patcherContext.UpdateMainProgress(string.Format(Properties.Resources.VerifyingFileName, patchFileInfo.Filename),
                                                       isIndeterminate: true,
                                                       isProgressbarVisible: true);

                    try
                    {
                        using (var fileStream =
                                   new FileStream(Path.Combine(PatchInfo.PatchName, patchFileInfo.Filename), FileMode.Open))
                        {
                            var actualHash = BitConverter.ToString(md5.ComputeHash(fileStream)).Replace("-", "")
                                             .ToLower();

                            if (actualHash != patchFileInfo.Md5Hash)
                            {
                                Log.Info(Properties.Resources.VerifyFailedMD5Hash, patchFileInfo.Filename, patchFileInfo.Md5Hash, actualHash);
                                list.Add(patchFileInfo);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Info(Properties.Resources.VerifyFailedException, patchFileInfo.Filename, ex.Message);
                        list.Add(patchFileInfo);
                    }
                }
            }

            Log.Info(Properties.Resources.FileVerificationComplete);
            _patcherContext.UpdateMainProgress(Properties.Resources.FileVerificationComplete);

            return(list);
        }
Beispiel #10
0
        private PatchSequence FindPatchSequence(int currentVersion = -1, int remoteVersion = -1)
        {
            if (currentVersion == -1)
            {
                currentVersion = _currentVersion;
            }
            if (remoteVersion == -1)
            {
                remoteVersion = _remoteVersion;
            }

            Log.Info("Attempting to find sequence from {0} to {1}", currentVersion, remoteVersion);
            var patchInfos = new List <PatchInfo>();
            var format     = "Attempting to patch from {0} to {1}. Currently checking {2}.";

            try
            {
                using (var webClient = new WebClient())
                {
                    if (currentVersion == 0)
                    {
                        PatcherContext.UpdateMainProgress(string.Format(format, 0,
                                                                        remoteVersion,
                                                                        remoteVersion), "", 0, true, true);
                        var patchInfo = GetPatchInfo(webClient, remoteVersion, $"{remoteVersion}_full.txt");
                        if (patchInfo == null)
                        {
                            throw new PatchSequenceNotFoundException(currentVersion, remoteVersion);
                        }
                        patchInfos.Add(patchInfo);
                    }
                    else
                    {
                        var fromNumber = currentVersion;
                        var toNumber   = remoteVersion;

                        while (fromNumber != toNumber)
                        {
                            PatcherContext.UpdateMainProgress(string.Format(format, currentVersion,
                                                                            remoteVersion,
                                                                            fromNumber), "", (fromNumber - (double)currentVersion / (remoteVersion - currentVersion)), true, true);
                            var patchInfo = GetPatchInfo(webClient, remoteVersion, $"{fromNumber}_to_{toNumber}.txt");

                            if (patchInfo != null)
                            {
                                patchInfos.Add(patchInfo);
                                fromNumber = toNumber;
                                toNumber  += 5;
                            }
                            else if (--toNumber == fromNumber)
                            {
                                return(FindPatchSequence(0, remoteVersion));
                            }
                        }
                    }
                }
            }
            finally
            {
                PatcherContext.UpdateMainProgress();
            }

            return(new PatchSequence(patchInfos));
        }