/// <summary> /// Writes the master servers file. /// </summary> /// <param name="info">The <see cref="MasterServerReadInfo"/>.</param> /// <param name="filePath">The file path to write to.</param> static void WriteMasterServersFile(MasterServerReadInfo info, string filePath) { // If we have nothing to write, just keep the old file instead of overwriting it with an empty file. Even though // the entries are probably outdated, its better to have outdated entries than nothing at all. if (info.MasterServers.Count() == 0) { return; } var sb = new StringBuilder(); foreach (var desc in info.MasterServers) { sb.AppendLine(desc.GetDescriptorString()); } lock (_ioSync) { // We will make 5 attempts to write the file before completely giving up for (var i = 0; i < 5; i++) { var tmpFile = Path.GetTempFileName(); try { // Write the text to the file then copy it over to the destination File.WriteAllText(tmpFile, sb.ToString()); File.Copy(tmpFile, filePath, true); // Success! break; } catch (Exception ex) { const string errmsg = "Failed to write master servers file `{0}`. Exception: {1}"; if (log.IsErrorEnabled) { log.ErrorFormat(errmsg, filePath, ex); } Debug.Fail(string.Format(errmsg, filePath, ex)); } finally { // Delete the temporary file PathHelper.SafeDeleteTempFile(tmpFile); } } } }
/// <summary> /// Initializes a new instance of the <see cref="MasterServerDownloader"/> class. /// </summary> /// <param name="masterReadInfo">The <see cref="MasterServerReadInfo"/> to add to.</param> /// <param name="sources">The <see cref="IDownloadSource"/> to use to download.</param> /// <param name="readVersion">The version of the <see cref="VersionFileList"/> to read, or null if reading /// the current version number.</param> public MasterServerDownloader(MasterServerReadInfo masterReadInfo, IEnumerable <IDownloadSource> sources, int?readVersion) { _readVersion = readVersion; _masterReadInfo = masterReadInfo; _sources = new List <IDownloadSource>(sources); // Cache the remote file path if (_readVersion.HasValue) { _remoteFileToDownload = PathHelper.GetVersionString(_readVersion.Value) + ".txt"; } else { _remoteFileToDownload = CurrentVersionFilePath; } }
/// <summary> /// The worker method for the reader threads. /// </summary> /// <param name="o">The arguments.</param> void ReadThreadWorker(object o) { var stateObj = (ThreadWorkerArgs)o; var callback = stateObj.Callback; var userState = stateObj.UserState; var readVersion = stateObj.Version; if (log.IsDebugEnabled) { log.DebugFormat("Running MasterServerReader worker. UserState: {0}. ReadVersion: {1}. Callback: {2}", userState, readVersion.HasValue ? readVersion.Value.ToString() : "[NULL]", callback); } var info = new MasterServerReadInfo(); if (readVersion.HasValue) info.AddVersion(readVersion.Value); // Create the master server readers from the file IEnumerable<DownloadSourceDescriptor> descriptors; lock (_ioSync) { descriptors = DownloadSourceDescriptor.FromDescriptorFile(LocalMasterServerListPath); } // Ensure we have descriptors if (descriptors.Count() == 0) { const string errmsg = "No DownloadSourceDescriptors could be found."; if (log.IsErrorEnabled) log.Error(errmsg); info.AppendError(errmsg); callback(this, info, userState); return; } // Create the source instances var sources = new List<IDownloadSource>(); foreach (var desc in descriptors) { try { var src = desc.Instantiate(); sources.Add(src); } catch (Exception ex) { const string errmsg = "Failed to instantiate DownloadSourceDescriptor `{0}`: {1}"; if (log.IsErrorEnabled) log.ErrorFormat(errmsg, desc, ex); info.AppendError(string.Format(errmsg, desc, ex)); } } // Ensure we have at least one source if (sources.Count == 0) { const string errmsg = "All DownloadSourceDescriptors failed to be instantiated - no servers available to use."; if (log.IsErrorEnabled) log.ErrorFormat(errmsg); info.AppendError(errmsg); callback(this, info, userState); return; } // Start the downloader using (var msd = new MasterServerDownloader(info, sources, readVersion) { DisposeSources = true }) { // This will block until its complete msd.Execute(); } // Save the new information to the files WriteMasterServersFile(info, LocalMasterServerListPath); WriteDownloadSourcesFile(info, LocalDownloadSourceListPath); // Invoke the callback if (callback != null) callback(this, info, userState); }
/// <summary> /// Initializes a new instance of the <see cref="MasterServerDownloader"/> class. /// </summary> /// <param name="masterReadInfo">The <see cref="MasterServerReadInfo"/> to add to.</param> /// <param name="sources">The <see cref="IDownloadSource"/> to use to download.</param> /// <param name="readVersion">The version of the <see cref="VersionFileList"/> to read, or null if reading /// the current version number.</param> public MasterServerDownloader(MasterServerReadInfo masterReadInfo, IEnumerable<IDownloadSource> sources, int? readVersion) { _readVersion = readVersion; _masterReadInfo = masterReadInfo; _sources = new List<IDownloadSource>(sources); // Cache the remote file path if (_readVersion.HasValue) _remoteFileToDownload = PathHelper.GetVersionString(_readVersion.Value) + ".txt"; else _remoteFileToDownload = CurrentVersionFilePath; }
/// <summary> /// Writes the master servers file. /// </summary> /// <param name="info">The <see cref="MasterServerReadInfo"/>.</param> /// <param name="filePath">The file path to write to.</param> static void WriteMasterServersFile(MasterServerReadInfo info, string filePath) { // If we have nothing to write, just keep the old file instead of overwriting it with an empty file. Even though // the entries are probably outdated, its better to have outdated entries than nothing at all. if (info.MasterServers.Count() == 0) return; var sb = new StringBuilder(); foreach (var desc in info.MasterServers) { sb.AppendLine(desc.GetDescriptorString()); } lock (_ioSync) { // We will make 5 attempts to write the file before completely giving up for (var i = 0; i < 5; i++) { var tmpFile = Path.GetTempFileName(); try { // Write the text to the file then copy it over to the destination File.WriteAllText(tmpFile, sb.ToString()); File.Copy(tmpFile, filePath, true); // Success! break; } catch (Exception ex) { const string errmsg = "Failed to write master servers file `{0}`. Exception: {1}"; if (log.IsErrorEnabled) log.ErrorFormat(errmsg, filePath, ex); Debug.Fail(string.Format(errmsg, filePath, ex)); } finally { // Delete the temporary file PathHelper.SafeDeleteTempFile(tmpFile); } } } }
/// <summary> /// The worker method for the reader threads. /// </summary> /// <param name="o">The arguments.</param> void ReadThreadWorker(object o) { var stateObj = (ThreadWorkerArgs)o; var callback = stateObj.Callback; var userState = stateObj.UserState; var readVersion = stateObj.Version; if (log.IsDebugEnabled) { log.DebugFormat("Running MasterServerReader worker. UserState: {0}. ReadVersion: {1}. Callback: {2}", userState, readVersion.HasValue ? readVersion.Value.ToString() : "[NULL]", callback); } var info = new MasterServerReadInfo(); if (readVersion.HasValue) { info.AddVersion(readVersion.Value); } // Create the master server readers from the file IEnumerable <DownloadSourceDescriptor> descriptors; lock (_ioSync) { descriptors = DownloadSourceDescriptor.FromDescriptorFile(LocalMasterServerListPath); } // Ensure we have descriptors if (descriptors.Count() == 0) { const string errmsg = "No DownloadSourceDescriptors could be found."; if (log.IsErrorEnabled) { log.Error(errmsg); } info.AppendError(errmsg); callback(this, info, userState); return; } // Create the source instances var sources = new List <IDownloadSource>(); foreach (var desc in descriptors) { try { var src = desc.Instantiate(); sources.Add(src); } catch (Exception ex) { const string errmsg = "Failed to instantiate DownloadSourceDescriptor `{0}`: {1}"; if (log.IsErrorEnabled) { log.ErrorFormat(errmsg, desc, ex); } info.AppendError(string.Format(errmsg, desc, ex)); } } // Ensure we have at least one source if (sources.Count == 0) { const string errmsg = "All DownloadSourceDescriptors failed to be instantiated - no servers available to use."; if (log.IsErrorEnabled) { log.ErrorFormat(errmsg); } info.AppendError(errmsg); callback(this, info, userState); return; } // Start the downloader using (var msd = new MasterServerDownloader(info, sources, readVersion) { DisposeSources = true }) { // This will block until its complete msd.Execute(); } // Save the new information to the files WriteMasterServersFile(info, LocalMasterServerListPath); WriteDownloadSourcesFile(info, LocalDownloadSourceListPath); // Invoke the callback if (callback != null) { callback(this, info, userState); } }