示例#1
0
        /// <summary>
        /// Creates a new <see cref="VersionFileList"/>.
        /// </summary>
        /// <param name="rootDir">The root directory containing the files to include.</param>
        /// <param name="filters">The filters to include.</param>
        /// <returns>The <see cref="VersionFileList"/> created from the given parameters.</returns>
        public static VersionFileList Create(string rootDir, IEnumerable <string> filters)
        {
            if (log.IsDebugEnabled)
            {
                log.DebugFormat("VersionFileList.Create(rootDir: {0}, fiters: ...)", rootDir);
            }

            var addFiles = new List <VersionFileInfo>();

            var files = Directory.GetFiles(rootDir, "*", SearchOption.AllDirectories);

            // Get the length of the root directory so we know how much to chop off so that each file starts relative to
            // the rootDir, and does not start with a path separator
            var rootDirLen = rootDir.Length;

            if (!rootDir.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
                !rootDir.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
            {
                rootDirLen++;
            }

            foreach (var f in files)
            {
                // Get the file information
                var fi = new FileInfo(f);

                // Generate the properties we are interested in
                var relativePath = fi.FullName.Substring(rootDirLen);
                var hash         = Hasher.GetFileHash(fi.FullName);
                var size         = fi.Length;

                // Add to the list
                var vfi = new VersionFileInfo(relativePath, hash, size);
                addFiles.Add(vfi);
            }

            var vfl = new VersionFileList(addFiles, filters);

            return(vfl);
        }
示例#2
0
        /// <summary>
        /// Creates the <see cref="VersionFileList"/> from a string.
        /// </summary>
        /// <param name="contents">The version file list contents.</param>
        /// <returns>The <see cref="VersionFileList"/> loaded from the <paramref name="contents"/>.</returns>
        /// <exception cref="InvalidDataException">Any of the lines are invalid.</exception>
        public static VersionFileList CreateFromString(string contents)
        {
            if (log.IsDebugEnabled)
                log.DebugFormat("VersionFileList.CreateFromString(contents: {0})", contents);

            var lines = contents.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            // Create the lists
            var files = new List<VersionFileInfo>();
            var filters = new List<string>();

            // Add to file list instead of the filters by default
            var addToFiles = true;

            var strComp = StringComparer.OrdinalIgnoreCase;

            foreach (var line in lines)
            {
                if (string.IsNullOrEmpty(line))
                    continue;

                var l = line.Trim();

                // Check for a header
                if (strComp.Equals(IncludeHeader, l))
                {
                    addToFiles = true;
                    continue;
                }
                else if (strComp.Equals(IgnoreHeader, l))
                {
                    addToFiles = false;
                    continue;
                }

                // Not a header, so split according to the type
                if (addToFiles)
                {
                    var vfi = VersionFileInfo.FromString(l);
                    files.Add(vfi);
                }
                else
                {
                    // Expect a line for a filter
                    if (l.Contains(Delimiter))
                    {
                        const string errmsg = "Was expecting a line containing a filter on line: {0}";
                        if (log.IsErrorEnabled)
                            log.ErrorFormat(errmsg, line);
                        throw new InvalidDataException(string.Format(errmsg, line));
                    }

                    filters.Add(l);
                }
            }

            var vfl = new VersionFileList(files, filters);
            return vfl;
        }
示例#3
0
        /// <summary>
        /// Creates a new <see cref="VersionFileList"/>.
        /// </summary>
        /// <param name="rootDir">The root directory containing the files to include.</param>
        /// <param name="filters">The filters to include.</param>
        /// <returns>The <see cref="VersionFileList"/> created from the given parameters.</returns>
        public static VersionFileList Create(string rootDir, IEnumerable<string> filters)
        {
            if (log.IsDebugEnabled)
                log.DebugFormat("VersionFileList.Create(rootDir: {0}, fiters: ...)", rootDir);

            var addFiles = new List<VersionFileInfo>();

            var files = Directory.GetFiles(rootDir, "*", SearchOption.AllDirectories);

            // Get the length of the root directory so we know how much to chop off so that each file starts relative to
            // the rootDir, and does not start with a path separator
            var rootDirLen = rootDir.Length;
            if (!rootDir.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
                !rootDir.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
                rootDirLen++;

            foreach (var f in files)
            {
                // Get the file information
                var fi = new FileInfo(f);

                // Generate the properties we are interested in
                var relativePath = fi.FullName.Substring(rootDirLen);
                var hash = Hasher.GetFileHash(fi.FullName);
                var size = fi.Length;

                // Add to the list
                var vfi = new VersionFileInfo(relativePath, hash, size);
                addFiles.Add(vfi);
            }

            var vfl = new VersionFileList(addFiles, filters);
            return vfl;
        }
示例#4
0
        /// <summary>
        /// The callback method for the <see cref="IMasterServerReader.BeginReadVersionFileList"/>.
        /// </summary>
        /// <param name="sender">The <see cref="IMasterServerReader"/> this event came from.</param>
        /// <param name="info">The information from the master server(s).</param>
        /// <param name="userState">An optional state object passed by the caller to supply information to the callback method
        /// from the method call.</param>
        void MasterServerReader_Callback_VersionFileList(IMasterServerReader sender, IMasterServerReadInfo info, object userState)
        {
            State = UpdateClientState.ReadingLiveVersionFileListDone;

            // Check for a valid VersionFileList
            if (string.IsNullOrEmpty(info.VersionFileListText))
            {
                const string errmsg =
                    "Could not get a valid VersionFileList file from the master servers for version `{0}` - download failed.";

                if (log.IsErrorEnabled)
                    log.ErrorFormat(errmsg, info.Version);

                if (MasterServerReaderError != null)
                    MasterServerReaderError(this, string.Format(errmsg, info.Version));

                HasErrors = true;
                return;
            }

            try
            {
                _versionFileList = VersionFileList.CreateFromString(info.VersionFileListText);
            }
            catch (Exception ex)
            {
                const string errmsg =
                    "Could not get a valid VersionFileList file from the master servers for version `{0}`. Exception: {1}";

                if (log.IsErrorEnabled)
                    log.ErrorFormat(errmsg, info.Version, ex);

                if (MasterServerReaderError != null)
                    MasterServerReaderError(this, string.Format(errmsg, info.Version, ex));

                HasErrors = true;
                return;
            }

            // Find the files to update
            var toUpdate = FindFilesToUpdate(_versionFileList);

            // If all file hashes match, then we are good to go
            if (toUpdate.Count() == 0)
            {
                CheckIfDownloadManagerComplete();
                return;
            }

            // There was one or more files to update, so start the updating...

            // Create the DownloadManager
            _dm = new DownloadManager(Settings.TargetPath, Settings.TempPath, info.Version);
            _dm.DownloadFinished += DownloadManager_DownloadFinished;
            _dm.FileMoveFailed += DownloadManager_FileMoveFailed;
            _dm.DownloadFailed += DownloadManager_DownloadFailed;
            _dm.Finished += DownloadManager_Finished;

            State = UpdateClientState.UpdatingFiles;

            // Add the sources to the DownloadManager
            var sources = info.DownloadSources.Select(x => x.Instantiate());
            _dm.AddSources(sources);

            // Enqueue the files that need to be downloaded
            _dm.Enqueue(toUpdate);
        }
示例#5
0
        /// <summary>
        /// Checks the files provided in the given <see cref="VersionFileList"/> and compares them to the local files
        /// to see what files need to be updated.
        /// </summary>
        /// <param name="vfl">The <see cref="VersionFileList"/> containing the files to be updated.</param>
        /// <returns>The relative paths to the files that need to be updated.</returns>
        IEnumerable<string> FindFilesToUpdate(VersionFileList vfl)
        {
            var ret = new List<string>();

            // Loop through each file
            foreach (var updateFileInfo in vfl.Files)
            {
                // Get the local file path
                var localFilePath = PathHelper.CombineDifferentPaths(Settings.TargetPath, updateFileInfo.FilePath);

                // If the file does not exist, add it
                if (!File.Exists(localFilePath))
                {
                    ret.Add(updateFileInfo.FilePath);
                    continue;
                }

                // Get the info for the local file
                try
                {
                    var localFileInfo = new FileInfo(localFilePath);

                    // If the size of the local file doesn't equal the size of the updated file, avoid
                    // checking the hash and just update it
                    if (localFileInfo.Length != updateFileInfo.Size)
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat(
                                "Update check on file `{0}`: File needs update - size mismatch (current: {1}, expected: {2}).",
                                updateFileInfo.FilePath, localFileInfo.Length, updateFileInfo.Size);
                        }

                        ret.Add(updateFileInfo.FilePath);
                        continue;
                    }

                    // File exists and is of the correct size, so compare the hash of the local file to the expected hash
                    var localFileHash = Hasher.GetFileHash(localFilePath);
                    if (!StringComparer.Ordinal.Equals(localFileHash, updateFileInfo.Hash))
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat(
                                "Update check on file `{0}`: File needs update - hash mismatch (current: {1}, expected: {2}).",
                                updateFileInfo.FilePath, localFileHash, updateFileInfo.Hash);
                        }

                        ret.Add(updateFileInfo.FilePath);
                        continue;
                    }
                }
                catch (IOException ex)
                {
                    const string errmsg =
                        "Failed to analyze file `{0}` to see if it needs to be updated. Will assume update is required. Exception: {1}";

                    if (log.IsErrorEnabled)
                        log.ErrorFormat(errmsg, updateFileInfo.FilePath, ex);

                    Debug.Fail(string.Format(errmsg, updateFileInfo.FilePath, ex));

                    // On an IOException, assume the file needs to be updated
                    ret.Add(updateFileInfo.FilePath);
                    continue;
                }

                if (log.IsDebugEnabled)
                    log.DebugFormat("Update check on file `{0}`: file is up-to-date.", updateFileInfo.FilePath);
            }

            if (log.IsInfoEnabled)
                log.InfoFormat("Found `{0}` files needing to be updated.", ret.Count);

            return ret;
        }
示例#6
0
        /// <summary>
        /// Creates the <see cref="VersionFileList"/> from a string.
        /// </summary>
        /// <param name="contents">The version file list contents.</param>
        /// <returns>The <see cref="VersionFileList"/> loaded from the <paramref name="contents"/>.</returns>
        /// <exception cref="InvalidDataException">Any of the lines are invalid.</exception>
        public static VersionFileList CreateFromString(string contents)
        {
            if (log.IsDebugEnabled)
            {
                log.DebugFormat("VersionFileList.CreateFromString(contents: {0})", contents);
            }

            var lines = contents.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            // Create the lists
            var files   = new List <VersionFileInfo>();
            var filters = new List <string>();

            // Add to file list instead of the filters by default
            var addToFiles = true;

            var strComp = StringComparer.OrdinalIgnoreCase;

            foreach (var line in lines)
            {
                if (string.IsNullOrEmpty(line))
                {
                    continue;
                }

                var l = line.Trim();

                // Check for a header
                if (strComp.Equals(IncludeHeader, l))
                {
                    addToFiles = true;
                    continue;
                }
                else if (strComp.Equals(IgnoreHeader, l))
                {
                    addToFiles = false;
                    continue;
                }

                // Not a header, so split according to the type
                if (addToFiles)
                {
                    var vfi = VersionFileInfo.FromString(l);
                    files.Add(vfi);
                }
                else
                {
                    // Expect a line for a filter
                    if (l.Contains(Delimiter))
                    {
                        const string errmsg = "Was expecting a line containing a filter on line: {0}";
                        if (log.IsErrorEnabled)
                        {
                            log.ErrorFormat(errmsg, line);
                        }
                        throw new InvalidDataException(string.Format(errmsg, line));
                    }

                    filters.Add(l);
                }
            }

            var vfl = new VersionFileList(files, filters);

            return(vfl);
        }
示例#7
0
        /// <summary>
        /// The callback method for the <see cref="IMasterServerReader.BeginReadVersionFileList"/>.
        /// </summary>
        /// <param name="sender">The <see cref="IMasterServerReader"/> this event came from.</param>
        /// <param name="info">The information from the master server(s).</param>
        /// <param name="userState">An optional state object passed by the caller to supply information to the callback method
        /// from the method call.</param>
        void MasterServerReader_Callback_VersionFileList(IMasterServerReader sender, IMasterServerReadInfo info, object userState)
        {
            State = UpdateClientState.ReadingLiveVersionFileListDone;

            // Check for a valid VersionFileList
            if (string.IsNullOrEmpty(info.VersionFileListText))
            {
                const string errmsg =
                    "Could not get a valid VersionFileList file from the master servers for version `{0}` - download failed.";

                if (log.IsErrorEnabled)
                {
                    log.ErrorFormat(errmsg, info.Version);
                }

                if (MasterServerReaderError != null)
                {
                    MasterServerReaderError(this, string.Format(errmsg, info.Version));
                }

                HasErrors = true;
                return;
            }

            try
            {
                _versionFileList = VersionFileList.CreateFromString(info.VersionFileListText);
            }
            catch (Exception ex)
            {
                const string errmsg =
                    "Could not get a valid VersionFileList file from the master servers for version `{0}`. Exception: {1}";

                if (log.IsErrorEnabled)
                {
                    log.ErrorFormat(errmsg, info.Version, ex);
                }

                if (MasterServerReaderError != null)
                {
                    MasterServerReaderError(this, string.Format(errmsg, info.Version, ex));
                }

                HasErrors = true;
                return;
            }

            // Find the files to update
            var toUpdate = FindFilesToUpdate(_versionFileList);

            // If all file hashes match, then we are good to go
            if (toUpdate.Count() == 0)
            {
                CheckIfDownloadManagerComplete();
                return;
            }

            // There was one or more files to update, so start the updating...

            // Create the DownloadManager
            _dm = new DownloadManager(Settings.TargetPath, Settings.TempPath, info.Version);
            _dm.DownloadFinished += DownloadManager_DownloadFinished;
            _dm.FileMoveFailed   += DownloadManager_FileMoveFailed;
            _dm.DownloadFailed   += DownloadManager_DownloadFailed;
            _dm.Finished         += DownloadManager_Finished;

            State = UpdateClientState.UpdatingFiles;

            // Add the sources to the DownloadManager
            var sources = info.DownloadSources.Select(x => x.Instantiate());

            _dm.AddSources(sources);

            // Enqueue the files that need to be downloaded
            _dm.Enqueue(toUpdate);
        }
示例#8
0
        /// <summary>
        /// Checks the files provided in the given <see cref="VersionFileList"/> and compares them to the local files
        /// to see what files need to be updated.
        /// </summary>
        /// <param name="vfl">The <see cref="VersionFileList"/> containing the files to be updated.</param>
        /// <returns>The relative paths to the files that need to be updated.</returns>
        IEnumerable <string> FindFilesToUpdate(VersionFileList vfl)
        {
            var ret = new List <string>();

            // Loop through each file
            foreach (var updateFileInfo in vfl.Files)
            {
                // Get the local file path
                var localFilePath = PathHelper.CombineDifferentPaths(Settings.TargetPath, updateFileInfo.FilePath);

                // If the file does not exist, add it
                if (!File.Exists(localFilePath))
                {
                    ret.Add(updateFileInfo.FilePath);
                    continue;
                }

                // Get the info for the local file
                try
                {
                    var localFileInfo = new FileInfo(localFilePath);

                    // If the size of the local file doesn't equal the size of the updated file, avoid
                    // checking the hash and just update it
                    if (localFileInfo.Length != updateFileInfo.Size)
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat(
                                "Update check on file `{0}`: File needs update - size mismatch (current: {1}, expected: {2}).",
                                updateFileInfo.FilePath, localFileInfo.Length, updateFileInfo.Size);
                        }

                        ret.Add(updateFileInfo.FilePath);
                        continue;
                    }

                    // File exists and is of the correct size, so compare the hash of the local file to the expected hash
                    var localFileHash = Hasher.GetFileHash(localFilePath);
                    if (!StringComparer.Ordinal.Equals(localFileHash, updateFileInfo.Hash))
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat(
                                "Update check on file `{0}`: File needs update - hash mismatch (current: {1}, expected: {2}).",
                                updateFileInfo.FilePath, localFileHash, updateFileInfo.Hash);
                        }

                        ret.Add(updateFileInfo.FilePath);
                        continue;
                    }
                }
                catch (IOException ex)
                {
                    const string errmsg =
                        "Failed to analyze file `{0}` to see if it needs to be updated. Will assume update is required. Exception: {1}";

                    if (log.IsErrorEnabled)
                    {
                        log.ErrorFormat(errmsg, updateFileInfo.FilePath, ex);
                    }

                    Debug.Fail(string.Format(errmsg, updateFileInfo.FilePath, ex));

                    // On an IOException, assume the file needs to be updated
                    ret.Add(updateFileInfo.FilePath);
                    continue;
                }

                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("Update check on file `{0}`: file is up-to-date.", updateFileInfo.FilePath);
                }
            }

            if (log.IsInfoEnabled)
            {
                log.InfoFormat("Found `{0}` files needing to be updated.", ret.Count);
            }

            return(ret);
        }
示例#9
0
        /// <summary>
        /// Adds the text read for the <see cref="VersionFileList"/>. This method will use a "best guess" approach
        /// to determine what text to use when multiple different texts are added.
        /// </summary>
        /// <param name="text">The text for the <see cref="VersionFileList"/>.</param>
        public void AddVersionFileListText(string text)
        {
            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Adding VersionFileList text `{0}` to MasterServerReadInfo `{1}`.", text, this);
            }

            lock (_versionFileListTextSync)
            {
                // If the text is exactly the same as the current _versionFileListText, then just ignore it since there is obviously
                // nothing to be done
                if (StringComparer.Ordinal.Equals(text, _versionFileListText))
                {
                    return;
                }

                // Try to parse the text as a VersionFileList to see if it is valid
                bool textIsValid;
                try
                {
                    VersionFileList.CreateFromString(text);
                    textIsValid = true;
                }
                catch (InvalidDataException)
                {
                    // Ignore InvalidDataException since its expected when the version is invalid
                    textIsValid = false;
                }
                catch (Exception ex)
                {
                    // For any other exception, it still must be invalid, but check it out when debugging
                    Debug.Fail(ex.ToString());
                    textIsValid = false;
                }

                // If no value set, just use the text no matter what
                if (string.IsNullOrEmpty(_versionFileListText))
                {
                    _versionFileListText          = text;
                    _currVersionFileListTextLegal = textIsValid;
                    return;
                }

                // The _versionFileListText already exists. If the current text is invalid but the new text is valid, then
                // just use the new text.
                if (!_currVersionFileListTextLegal && textIsValid)
                {
                    _versionFileListText          = text;
                    _currVersionFileListTextLegal = textIsValid;
                    return;
                }

                // Likewise, if the current text is valid but the new text is invalid, do not use the new text
                if (_currVersionFileListTextLegal && !textIsValid)
                {
                    return;
                }

                // From here, they are either both valid or both invalid. To keep things simple, just assume that the larger
                // of the two strings are "better". So change to the new text if it is longer.
                if (text.Length > _versionFileListText.Length)
                {
                    _versionFileListText          = text;
                    _currVersionFileListTextLegal = textIsValid;
                    return;
                }
            }
        }