private async Task GenerateManifestAsync(EManifestType manifestType) { this.TokenSource = new CancellationTokenSource(); this.GenerateGameManifestButton.Sensitive = false; this.GenerateLaunchpadManifestButton.Sensitive = false; var targetDirectory = this.FolderChooser.Filename; try { await this.Manifest.GenerateManifestAsync ( targetDirectory, manifestType, this.ProgressReporter, this.TokenSource.Token ); this.StatusLabel.Text = this.LocalizationCatalog.GetString("Finished"); } catch (TaskCanceledException) { this.StatusLabel.Text = this.LocalizationCatalog.GetString("Cancelled"); this.MainProgressBar.Fraction = 0; } this.GenerateGameManifestButton.Sensitive = true; this.GenerateLaunchpadManifestButton.Sensitive = true; }
/// <summary> /// Gets the specifed manifest currently held by the launcher. The return value of this method may be null if no /// manifest could be retrieved. /// </summary> /// <param name="manifestType">The type of manifest to retrieve, that is, the manifest for a specific component.</param> /// <param name="getOldManifest">Whether or not the old manifest or the new manifest should be retrieved.</param> /// <returns>A list of <see cref="ManifestEntry"/> objects.</returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="manifestType"/> is not a known value.</exception> public IReadOnlyList <ManifestEntry> GetManifest(EManifestType manifestType, bool getOldManifest) { switch (manifestType) { case EManifestType.Game: case EManifestType.Launchpad: { lock (this.ManifestsLock) { if (getOldManifest) { if (this.OldManifests.ContainsKey(manifestType)) { return(this.OldManifests[manifestType]); } } else { if (this.Manifests.ContainsKey(manifestType)) { return(this.Manifests[manifestType]); } } } return(null); } default: { throw new ArgumentOutOfRangeException(nameof(manifestType), "An unknown manifest type was requested."); } } }
/// <summary> /// Reloads all manifests of the specifed type from disk. /// </summary> /// <param name="manifestType">The type of manifest to reload.</param> public void ReloadManifests(EManifestType manifestType) { lock (this.ManifestsLock) { var newManifestPath = GetManifestPath(manifestType, false); var oldManifestPath = GetManifestPath(manifestType, true); // Reload new manifests if (!File.Exists(newManifestPath)) { this.Manifests.AddOrUpdate(manifestType, null); } else { this.Manifests.AddOrUpdate(manifestType, LoadManifest(newManifestPath)); } // Reload old manifests if (!File.Exists(oldManifestPath)) { this.OldManifests.AddOrUpdate(manifestType, null); } else { this.OldManifests.AddOrUpdate(manifestType, LoadManifest(oldManifestPath)); } } }
/// <summary> /// Gets the manifest URL for the specified manifest type. /// </summary> /// <param name="manifestType">The type of manifest to get the URL of.</param> /// <returns>The game manifest URL.</returns> public string GetManifestChecksumURL(EManifestType manifestType) { if (manifestType == EManifestType.Launchpad) { return($"{this.RemoteURL.LocalPath}/launcher/{manifestType}Manifest.checksum"); } return($"{this.RemoteURL.LocalPath}/game/{this.SystemTarget}/{manifestType}Manifest.checksum"); }
/// <summary> /// Gets the manifest URL for the specified manifest type. /// </summary> /// <param name="manifestType">The type of manifest to get the URL of.</param> /// <returns>The game manifest URL.</returns> public string GetManifestURL(EManifestType manifestType) { if (manifestType == EManifestType.Launchpad) { return($"{this.RemoteURL}/launcher/{manifestType}Manifest.txt"); } return($"{this.RemoteURL}/game/{this.SystemTarget}/{manifestType}Manifest.txt"); }
/// <summary> /// Generates a manifest containing the relative path, MD5 hash and file size from /// all files in the provided root path. /// </summary> /// <param name="rootPath">The root path of the directory the manifest should represent.</param> /// <param name="InManifestType">The type of manifest that should be generated.</param> public void GenerateManifest(string rootPath, EManifestType InManifestType) { TargetPath = rootPath; ManifestType = InManifestType; Thread t = new Thread(GenerateManifest_Implementation); t.Start(); }
/// <summary> /// Generates a manifest containing the relative path, MD5 hash and file size from /// all files in the provided root path. /// </summary> /// <param name="targetPath">The root path of the directory the manifest should represent.</param> /// <param name="manifestType">The type of manifest that should be generated.</param> public void GenerateManifest(string targetPath, EManifestType manifestType) { Thread t = new Thread(() => GenerateManifest_Implementation(targetPath, manifestType)) { Name = "GenerateManifest" }; t.Start(); }
/// <summary> /// Gets the specified manifest's path on disk. The presence of the manifest is not guaranteed at /// this point. /// </summary> /// <param name="manifestType">The type of manifest to get the path to.</param> /// <param name="getOldManifestPath">Whether or not the path should specify an old manifest.</param> /// <returns>A fully qualified path to where a manifest should be.</returns> public string GetManifestPath(EManifestType manifestType, bool getOldManifestPath) { var manifestPath = Path.Combine(this.LocalBaseDirectory, $"{manifestType}Manifest.txt"); if (getOldManifestPath) { manifestPath += ".old"; } return(manifestPath); }
/// <summary> /// Gets the specified manifest's path on disk. The presence of the manifest is not guaranteed at /// this point. /// </summary> /// <param name="manifestType">The type of manifest to get the path to.</param> /// <param name="getOldManifestPath">Whether or not the path should specify an old manifest.</param> /// <returns>A fully qualified path to where a manifest should be.</returns> public string GetManifestPath(EManifestType manifestType, bool getOldManifestPath) { string manifestPath = $@"{this.LocalBaseDirectory}{manifestType}Manifest.txt"; if (getOldManifestPath) { manifestPath += ".old"; } return(manifestPath); }
/// <summary> /// Generates a manifest containing the relative path, MD5 hash and file size from /// all files in the provided root path. /// </summary> /// <param name="targetPath">The root path of the directory the manifest should represent.</param> /// <param name="manifestType">The type of manifest that should be generated.</param> /// <param name="progressReporter">The progress reporter to use.</param> /// <param name="ct">The cancellation token to use.</param> public Task GenerateManifestAsync ( string targetPath, EManifestType manifestType, IProgress <ManifestGenerationProgressChangedEventArgs> progressReporter, CancellationToken ct ) { var parentDirectory = Directory.GetParent(targetPath).ToString(); var manifestPath = Path.Combine(parentDirectory, $"{manifestType}Manifest.txt"); var manifestChecksumPath = Path.Combine(parentDirectory, $"{manifestType}Manifest.checksum"); return(Task.Run ( async() => { var manifestFilePaths = new List <string>(Directory .EnumerateFiles(targetPath, "*", SearchOption.AllDirectories) .Where(s => !IsPathABlacklistedFile(s))); this.GenerationProgressArgs.TotalFiles = manifestFilePaths.Count; using (var tw = new StreamWriter(File.Create(manifestPath, 4096, FileOptions.Asynchronous))) { var completedFiles = 0; foreach (var filePath in manifestFilePaths) { ct.ThrowIfCancellationRequested(); var newEntry = CreateEntryForFile(targetPath, filePath); await tw.WriteLineAsync(newEntry.ToString()); await tw.FlushAsync(); completedFiles++; this.GenerationProgressArgs.CompletedFiles = completedFiles; this.GenerationProgressArgs.Filepath = newEntry.RelativePath; this.GenerationProgressArgs.Hash = newEntry.Hash; this.GenerationProgressArgs.Filesize = newEntry.Size; progressReporter.Report(this.GenerationProgressArgs); } } await CreateManifestChecksumAsync(manifestPath, manifestChecksumPath); }, ct )); }
/// <summary> /// The asynchronous implementation of the GenerateManifest function. /// </summary> /// <param name="targetPath">The root path of the directory the manifest should represent.</param> /// <param name="manifestType">The type of manifest that should be generated.</param> private void GenerateManifest_Implementation(string targetPath, EManifestType manifestType) { string parentDirectory = Directory.GetParent(targetPath).ToString(); string manifestPath = $@"{parentDirectory}{Path.DirectorySeparatorChar}{manifestType}Manifest.txt"; string manifestChecksumPath = $@"{parentDirectory}{Path.DirectorySeparatorChar}{manifestType}Manifest.checksum"; List <string> manifestFilePaths = new List <string>(Directory .EnumerateFiles(targetPath, "*", SearchOption.AllDirectories) .Where(s => !IsPathABlacklistedFile(s))); using (TextWriter tw = new StreamWriter(File.Create(manifestPath))) { int completedFiles = 0; foreach (string filePath in manifestFilePaths) { ManifestEntry newEntry = CreateEntryForFile(targetPath, filePath); tw.WriteLine(newEntry); tw.Flush(); completedFiles++; GenerationProgressArgs.TotalFiles = manifestFilePaths.Count; GenerationProgressArgs.CompletedFiles = completedFiles; GenerationProgressArgs.Filepath = newEntry.RelativePath; GenerationProgressArgs.Hash = newEntry.Hash; GenerationProgressArgs.Filesize = newEntry.Size; OnManifestGenerationProgressChanged(); } } // Create a checksum file for the manifest. using (Stream manifestStream = File.OpenRead(manifestPath)) { string manifestHash = MD5Handler.GetStreamHash(manifestStream); using (FileStream checksumStream = File.Create(manifestChecksumPath)) { using (TextWriter tw = new StreamWriter(checksumStream)) { tw.WriteLine(manifestHash); tw.Close(); } } } OnManifestGenerationFinished(); }
/// <summary> /// Reloads all manifests of the specifed type from disk. /// </summary> /// <param name="manifestType">The type of manifest to reload.</param> public void ReloadManifests(EManifestType manifestType) { lock (this.ManifestsLock) { string newManifestPath = GetManifestPath(manifestType, false); string oldManifestPath = GetManifestPath(manifestType, true); // Reload new manifests try { if (!File.Exists(newManifestPath)) { this.Manifests.AddOrUpdate(manifestType, null); } this.Manifests.AddOrUpdate(manifestType, LoadManifest(newManifestPath)); } catch (IOException ioex) { Log.Warn($"Could not load manifest of type {manifestType} (IOException): " + ioex.Message); } // Reload old manifests try { if (!File.Exists(oldManifestPath)) { this.OldManifests.AddOrUpdate(manifestType, null); } this.OldManifests.AddOrUpdate(manifestType, LoadManifest(oldManifestPath)); } catch (IOException ioex) { Log.Warn($"Could not load old manifest of type {manifestType} (IOException): " + ioex.Message); } } }
/// <summary> /// Gets the manifest URL for the specified manifest type. /// </summary> /// <returns>The game manifest URL.</returns> public string GetManifestChecksumURL(EManifestType manifestType) { string manifestURL = $"{this.RemoteURL}/game/{this.SystemTarget}/{manifestType}Manifest.checksum"; return(manifestURL); }
/// <summary> /// The asynchronous implementation of the GenerateManifest function. /// </summary> /// <param name="targetPath">The root path of the directory the manifest should represent.</param> /// <param name="manifestType">The type of manifest that should be generated.</param> private void GenerateManifest_Implementation(string targetPath, EManifestType manifestType) { string parentDirectory = Directory.GetParent(targetPath).ToString(); string manifestPath = $@"{parentDirectory}{Path.DirectorySeparatorChar}{manifestType}Manifest.txt"; string manifestChecksumPath = $@"{parentDirectory}{Path.DirectorySeparatorChar}{manifestType}Manifest.checksum"; List <string> manifestFilePaths = new List <string>(Directory .EnumerateFiles(targetPath, "*", SearchOption.AllDirectories) .Where(s => !s.EndsWith(".install") && !s.EndsWith(".update"))); using (TextWriter tw = new StreamWriter(File.Create(manifestPath))) { int completedFiles = 0; foreach (string filePath in manifestFilePaths) { // Calculate the MD5 hash of the file string hash; using (FileStream fileStream = File.OpenRead(filePath)) { hash = MD5Handler.GetStreamHash(fileStream); } // Get the file size on disk FileInfo fileInfo = new FileInfo(filePath); long fileSize = fileInfo.Length; // Get the relative path of the file string relativeFilePath = filePath.Substring(targetPath.Length); // Write the entry to the manifest ManifestEntry newEntry = new ManifestEntry { RelativePath = relativeFilePath, Hash = hash, Size = fileSize }; tw.WriteLine(newEntry); completedFiles++; GenerationProgressArgs.Filepath = relativeFilePath; GenerationProgressArgs.TotalFiles = manifestFilePaths.Count; GenerationProgressArgs.CompletedFiles = completedFiles; GenerationProgressArgs.Hash = hash; GenerationProgressArgs.Filesize = fileSize; OnManifestGenerationProgressChanged(); } } // Create a checksum file for the manifest. using (Stream manifestStream = File.OpenRead(manifestPath)) { string manifestHash = MD5Handler.GetStreamHash(manifestStream); using (FileStream checksumStream = File.Create(manifestChecksumPath)) { using (TextWriter tw = new StreamWriter(checksumStream)) { tw.WriteLine(manifestHash); tw.Close(); } } } OnManifestGenerationFinished(); }
static void Main(string[] args) { List <string> Arguments = new List <string>(args); if (args.Length > 0) { if (Arguments.Contains(BatchSwitch)) { // Don't load the UI - instead, run the manifest generation directly Console.WriteLine("[Info]: Running in batch mode."); EManifestType ManifestType = EManifestType.Game; if (Arguments.Contains(ManifestTypeSwitch)) { if (Arguments.IndexOf(ManifestTypeSwitch) != args.Length - 1) { string targetManifest = Arguments[(Arguments.IndexOf(ManifestTypeSwitch) + 1)]; if (EManifestType.Game.ToString() == targetManifest) { ManifestType = EManifestType.Game; } else if (EManifestType.Launchpad.ToString() == targetManifest) { ManifestType = EManifestType.Launchpad; } else { Console.WriteLine("[Warning]: The '-m' manifest switch must be followed by either 'Game' or 'Launcher'."); } } else { Console.WriteLine("[Warning]: The '-m' manifest switch must be followed by either 'Game' or 'Launcher'."); } } if (Arguments.Contains(DirectorySwitch)) { if (Arguments.IndexOf(DirectorySwitch) != args.Length - 1) { string TargetDirectory = Arguments[(Arguments.IndexOf(DirectorySwitch) + 1)].TrimEnd(Path.DirectorySeparatorChar); Console.WriteLine(TargetDirectory); if (Directory.Exists(TargetDirectory)) { Console.WriteLine("[Info]: Generating manifest..."); ManifestHandler Manifest = new ManifestHandler(); Manifest.ManifestGenerationProgressChanged += OnProgressChanged; Manifest.ManifestGenerationFinished += OnGenerationFinished; Manifest.GenerateManifest(TargetDirectory, ManifestType); } else { Console.WriteLine("[Warning]: The '-d' directory switch must be followed by a valid directory."); } } else { Console.WriteLine("[Warning]: The '-d' directory switch must be followed by a valid directory."); } } else { Console.WriteLine("[Warning]: No directory provided for batch mode, using working directory."); Console.WriteLine("[Info]: Generating manifest..."); ManifestHandler Manifest = new ManifestHandler(); Manifest.ManifestGenerationProgressChanged += OnProgressChanged; Manifest.ManifestGenerationFinished += OnGenerationFinished; Manifest.GenerateManifest(Directory.GetCurrentDirectory(), ManifestType); } } else { Console.WriteLine("[Info]: Run the program with -b to enable batch mode. Use -d <directory> to select the target directory, or omit it to use the working directory. Use -m [Game|Launcher] to select the type of manifest (default is Game)."); } } else { // run a GTK UI instead of WinForms Gtk.Application.Init(); MainWindow win = new MainWindow(); win.Show(); Gtk.Application.Run(); } }