diff --git a/installer/RePlaysTV-Installer/CommandLineProcess.cs b/installer/RePlaysTV-Installer/CommandLineProcess.cs new file mode 100644 index 0000000..c23fc4a --- /dev/null +++ b/installer/RePlaysTV-Installer/CommandLineProcess.cs @@ -0,0 +1,156 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using RePlaysTV_Installer.Views; + +namespace RePlaysTV_Installer +{ + internal sealed class CommandLineProcess : IDisposable + { + private readonly string _workDirectory; + private bool _startImport; + + public CommandLineProcess(string workDirectory) + { + _workDirectory = string.IsNullOrEmpty(workDirectory) ? null : workDirectory; + Process = new Process + { + StartInfo = + { + FileName = "cmd.exe", + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8 + } + }; + + Process.OutputDataReceived += SortOutputHandler; + Process.ErrorDataReceived += SortOutputHandler; + } + + private Process Process { get; } + + private StreamWriter StreamWriter { get; set; } + + public void Dispose() + { + Process?.Dispose(); + StreamWriter?.Dispose(); + } + + public async void SetupStreamWriterWithEncoding(string encoding = "chcp 65001") + { + if (string.IsNullOrWhiteSpace(encoding)) throw new ArgumentException(nameof(encoding)); + + StreamWriter = Process?.StandardInput; + + if (StreamWriter == null) + throw new InvalidOperationException( + "There was a problem with initializing the stream writer for the command line process."); + + await StreamWriter?.WriteLineAsync(encoding); + } + + public void StartCommandLineProcess() + { + // run as console app + Main.Log("Initializing Updater"); + + if (Process == null) + throw new InvalidOperationException( + "The command line for the whole execution was not initialized correct."); + + Process.Start(); + Process.BeginOutputReadLine(); + Process.BeginErrorReadLine(); + } + + private async void SortOutputHandler(object sendingProcess, DataReceivedEventArgs dataReceivedEventArgs) + { + if (string.IsNullOrEmpty(dataReceivedEventArgs.Data)) + { + return; + } + + if (dataReceivedEventArgs.Data.Contains("All rights reserved.")) + { + Main.Log("Ready"); + } + else if (dataReceivedEventArgs.Data.Contains("We will now attempt to import: ") && !_startImport) + { + //part two of installation + _startImport = true; + await Installer.StartImport(StreamWriter); + Main.Log("======================================="); + Main.Log("======================================="); + Main.Log("======================================="); + Main.Log("This next Process will take awhile (with no sign of progress)... Please be patient."); + ; + } + else + { + if (dataReceivedEventArgs.Data.Contains("npm install") || + dataReceivedEventArgs.Data.Contains("electron-forge package") && + !dataReceivedEventArgs.Data.Contains("\"electron-forge package\"") || + dataReceivedEventArgs.Data.Contains("asar extract")) + { + Main.Log("======================================="); + Main.Log("======================================="); + Main.Log("======================================="); + Main.Log( + $"[{DateTime.Now:h:mm:ss tt}] This next Process will take awhile (with no sign of progress)... Please be patient."); + ; + } + + if (dataReceivedEventArgs.Data.Contains("Thanks for using ") && dataReceivedEventArgs.Data.Contains("electron-forge")) + { + await Installer.StartModify(StreamWriter); + } + + if (dataReceivedEventArgs.Data.Contains("npm ERR!") || + dataReceivedEventArgs.Data.Contains("unhandled error") || + dataReceivedEventArgs.Data.Contains("Error: ")) + { + var message = + "An unhandled error has occurred during the install, It is possible that the installation has failed.\nTry restarting your computer and turn off anti-virus before installing.\n\nReport this issue by copying the logs and sending it to a developer."; + Main.ShowMessageBox(message); + } + + if (dataReceivedEventArgs.Data.Contains("'nodejs-portable.exe' is not recognized")) + { + var message = + "'nodejs-portable.exe' is missing from the working directory.\n\nMake sure you properly extracted the installer to a folder."; + Main.ShowMessageBox(message); + } + + if (dataReceivedEventArgs.Data.Contains(">exit")) + { + Main.Log("======================================="); + Main.Log("======================================="); + Main.Log("======================================="); + Main.Log("Installation Complete!"); + Main.InstallComplete(); + } + + Main.Log(dataReceivedEventArgs.Data); + } + } + + public async Task ExecuteMainTaskAsync() + { + if ((StreamWriter == null) | !await Installer.DownloadPlaysSetup(_workDirectory)) + { + return; + } + + Installer.ListInstalledAntivirusProducts(); + await Installer.StartExtract(StreamWriter, _workDirectory); + } + } +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Helper/AsynchronousFileHelper.cs b/installer/RePlaysTV-Installer/Helper/AsynchronousFileHelper.cs new file mode 100644 index 0000000..ca428fd --- /dev/null +++ b/installer/RePlaysTV-Installer/Helper/AsynchronousFileHelper.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace RePlaysTV_Installer.Helper +{ + public static class AsynchronousFileHelper + { + /// + /// This is the same default buffer size as + /// and . + /// + private const int DefaultBufferSize = 4096; + + /// + /// Indicates that + /// 1. The file is to be used for asynchronous reading. + /// 2. The file is to be accessed sequentially from beginning to end. + /// + private const FileOptions DefaultOptions = FileOptions.Asynchronous | FileOptions.SequentialScan; + + public static async Task ReadAllLinesAsync(string path) + { + return await ReadAllLinesAsync(path, Encoding.UTF8); + } + + public static async Task ReadAllLinesAsync(string path, Encoding encoding) + { + var lines = new List(); + + // Open the FileStream with the same FileMode, FileAccess + // and FileShare as a call to File.OpenText would've done. + using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, + DefaultOptions)) + using (var reader = new StreamReader(stream, encoding)) + { + string line; + while ((line = await reader.ReadLineAsync()) != null) lines.Add(line); + } + + return lines.ToArray(); + } + + public static async Task WriteAllLinesAsync(string path, List linesToWrite) + { + await WriteAllLinesAsync(path, Encoding.UTF8, linesToWrite.ToArray()); + } + + public static async Task WriteAllLinesAsync(string path, IEnumerable linesToWrite) + { + await WriteAllLinesAsync(path, Encoding.UTF8, linesToWrite); + } + + public static async Task WriteAllLinesAsync(string path, Encoding encoding, IEnumerable linesToWrite) + { + // Open the FileStream with the same FileMode, FileAccess + // and FileShare as a call to File.OpenText would've done. + using (var stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, + DefaultBufferSize, DefaultOptions)) + using (var writer = new StreamWriter(stream, encoding)) + { + foreach (var line in linesToWrite) await writer.WriteLineAsync(line); + } + } + } +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Installer.cs b/installer/RePlaysTV-Installer/Installer.cs index 3b89ce9..4a8e251 100644 --- a/installer/RePlaysTV-Installer/Installer.cs +++ b/installer/RePlaysTV-Installer/Installer.cs @@ -1,227 +1,292 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Management; using System.Net; using System.Security.Cryptography; -using System.Text; -using System.Threading; using System.Threading.Tasks; -using System.Windows.Forms; +using RePlaysTV_Installer.Helper; +using RePlaysTV_Installer.Settings; +using RePlaysTV_Installer.Views; -namespace RePlaysTV_Installer { - class Installer { - public static string rePlaysDirectory = Environment.GetEnvironmentVariable("LocalAppData") + "\\RePlays"; - public static Dictionary installSettings = - new Dictionary () +namespace RePlaysTV_Installer +{ + internal sealed class Installer + { + public static void ListInstalledAntivirusProducts() { - { "playsSetupUrl", "https://web.archive.org/web/20191212211927if_/https://app-updates.plays.tv/builds/PlaysSetup.exe" }, - { "ltcVersion", "0.54.7" }, - { "cleanInstall", true }, - { "deleteTemp", false }, - { "ignoreChecksum", false }, - }; - public static void ListInstalledAntivirusProducts(RichTextBox richTextBox1 = null) { using (var searcher = new ManagementObjectSearcher(@"\\" + - Environment.MachineName + - @"\root\SecurityCenter2", - "SELECT * FROM AntivirusProduct")) { + Environment.MachineName + + @"\root\SecurityCenter2", + "SELECT * FROM AntivirusProduct")) + { var searcherInstance = searcher.Get(); - var msg = "Detected installed antivirus(es), may conflict with the installation: "; - if(searcherInstance.Count < 1) { - foreach (var instance in searcherInstance) { - msg = msg + instance["displayName"].ToString() + ", "; + Main.Log("Detected installed antivirus(es), may conflict with the installation: "); + + if (searcherInstance.Count < 1) + { + foreach (var instance in searcherInstance) + { + Main.Log($"{instance["displayName"]},"); } - } - else { - msg = "No installed antivirus detected."; + + return; } - Log(msg, richTextBox1); + Main.Log("No installed antivirus detected."); } } - public static void ListFilesInDir(StreamWriter SW, string dir, RichTextBox richTextBox1 = null) { - Log("Displaying tree view of '" + dir + "' for debugging purposes:", richTextBox1); - SW.WriteLine("tree \"" + dir + "\" /f"); + public async Task ListFilesInDir(StreamWriter SW, string dir) + { + Main.Log("Displaying tree view of '" + dir + "' for debugging purposes:"); + await SW.WriteLineAsync("tree \"" + dir + "\" /f"); } - public static async Task DownloadSetup(RichTextBox richTextBox1 = null, string workDirectory = null) { //part one of installation - if (workDirectory == null) workDirectory = Directory.GetCurrentDirectory(); - - var correctHash = "3a7cea84d50ad2c31a79e66f5c3f3b8d"; + public static async Task DownloadPlaysSetup(string workDirectory = null) + { + //part one of installation + workDirectory = workDirectory ?? Directory.GetCurrentDirectory(); + var correctHash = InstallerSettings.GetInstallerSetting(InstallerSetting.CorrectPlaysSetupHash); // Checksum - if (File.Exists(workDirectory + "\\PlaysSetup.exe")) { - if ((bool)installSettings["ignoreChecksum"] == false) { - bool checksumPass = false; - using (var md5 = MD5.Create()) { - using (var stream = File.OpenRead(workDirectory + "\\PlaysSetup.exe")) { - var hash = md5.ComputeHash(stream); - var hashAsString = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); - - if (correctHash == hashAsString) { - checksumPass = true; - Log("PlaysSetup.exe passed MD5 checksum: " + BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(), richTextBox1); - } else { - checksumPass = false; - Log("PlaysSetup.exe did not pass MD5 checksum!!!", richTextBox1); - } + if (File.Exists(workDirectory + "\\PlaysSetup.exe") && + !InstallerSettings.GetInstallerSetting(InstallerSetting.IgnoreChecksum)) + { + using (var md5 = MD5.Create()) + { + Main.Log("Check if executable has correct hash."); + using (var stream = File.OpenRead(workDirectory + "\\PlaysSetup.exe")) + { + var hashAsString = BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "") + .ToLowerInvariant(); + if (correctHash == hashAsString) + { + Main.Log($"PlaysSetup.exe has the correct MD5: {hashAsString}"); + return true; } } - if (!checksumPass) - File.Delete(workDirectory + "\\PlaysSetup.exe"); - else return; - } else return; + } + + // PlaysSetup.exe did not pass MD5 checksum!!! + Main.Log( + $"The checksum found on PlaysSetup was not the one needed.{Environment.NewLine}The file will be deleted.{Environment.NewLine}Please restart installation."); + File.Delete(workDirectory + "\\PlaysSetup.exe"); + return false; } - Log("PlaysSetup.exe missing or failed checksum, starting download", richTextBox1); - using (var client = new WebClient()) { - client.DownloadProgressChanged += (o, args) => { - Log("Downloading PlaysSetup.exe @ web.archive.org: " + args.BytesReceived + " / 145310344 Bytes", richTextBox1); + Main.Log("PlaysSetup.exe missing or failed checksum, starting download"); + using (var client = new WebClient()) + { + var playSetupExecutableSizeInBytes = + InstallerSettings.GetInstallerSetting(InstallerSetting.PlaySetupExecutableSizeInBytes); + var playsSetupExecutableSizeInMb = Math.Round(playSetupExecutableSizeInBytes / 1000000, 2); + client.DownloadProgressChanged += (o, args) => + { + var bytesReceivedInMegabyte = args.BytesReceived / 1000000; + var progressInPercent = + decimal.Round(decimal.Divide(bytesReceivedInMegabyte, playsSetupExecutableSizeInMb) * 100, 2); + Main.Log( + $"Downloading PlaysSetup.exe @ web.archive.org: {bytesReceivedInMegabyte}/{playsSetupExecutableSizeInMb} MB {progressInPercent}%"); }; - client.DownloadFileCompleted += async (o, args) => { - Log("Finished downloading PlaysSetup.exe, doing a checksum", richTextBox1); - await DownloadSetup(richTextBox1, workDirectory); + + client.DownloadFileCompleted += async (o, args) => + { + Main.Log("Finished downloading PlaysSetup.exe, doing a checksum"); + await DownloadPlaysSetup(workDirectory); }; + await client.DownloadFileTaskAsync( - new Uri((string) installSettings["playsSetupUrl"]), + new Uri(InstallerSettings.GetInstallerSetting(InstallerSetting.PlaysSetupUrl)), workDirectory + "\\PlaysSetup.exe"); } + + return false; } - public static void StartExtract(StreamWriter SW, string workDirectory=null) { //part one of installation - if (workDirectory == null) workDirectory = Directory.GetCurrentDirectory(); - else SW.WriteLine("cd /d \"" + workDirectory + "\""); + public static async Task StartExtract(StreamWriter sw, string workDirectory = null) + { + //part one of installation + if (workDirectory != null) + { + await sw.WriteLineAsync("cd /d \"" + workDirectory + "\""); + } + + workDirectory = workDirectory ?? Directory.GetCurrentDirectory(); + Main.Log($"Starting to work on the folder {workDirectory}"); - SW.WriteLine("nodejs-portable.exe"); - if (Directory.Exists(workDirectory + "\\temp") && (bool)installSettings["cleanInstall"] == true) { - SW.WriteLine("rd /s /q temp"); + await sw.WriteLineAsync("nodejs-portable.exe"); + if (Directory.Exists(workDirectory + "\\temp") && + InstallerSettings.GetInstallerSetting(InstallerSetting.CleanInstall)) + { + await sw.WriteLineAsync("rd /s /q temp"); } - SW.WriteLine("mkdir temp"); - SW.WriteLine("7z e PlaysSetup.exe -o.\\PlaysSetup -aos"); - SW.WriteLine("copy /Y .\\PlaysSetup\\Update.exe .\\Update.exe"); - SW.WriteLine("7z x .\\PlaysSetup\\Plays-3.0.0-full.nupkg -o.\\PlaysSetup\\Plays-3.0.0-full -aos"); - SW.WriteLine("asar extract .\\PlaysSetup\\Plays-3.0.0-full\\lib\\net45\\resources\\app.asar temp"); - SW.WriteLine("cd temp"); - SW.WriteLine("npm init -f"); - SW.WriteLine("npm install"); - SW.WriteLine("electron-forge import"); + + await sw.WriteLineAsync("mkdir temp"); + await sw.WriteLineAsync("7z e PlaysSetup.exe -o.\\PlaysSetup -aos"); + await sw.WriteLineAsync("copy /Y .\\PlaysSetup\\Update.exe .\\Update.exe"); + await sw.WriteLineAsync( + "7z x .\\PlaysSetup\\Plays-3.0.0-full.nupkg -o.\\PlaysSetup\\Plays-3.0.0-full -aos"); + await sw.WriteLineAsync( + "asar extract .\\PlaysSetup\\Plays-3.0.0-full\\lib\\net45\\resources\\app.asar temp"); + await sw.WriteLineAsync("cd temp"); + await sw.WriteLineAsync("npm init -f"); + await sw.WriteLineAsync("npm install"); + await sw.WriteLineAsync("electron-forge import"); } - public static void StartImport(StreamWriter SW) { //part two of installation - Thread.Sleep(5000); - SW.WriteLine("y"); - Thread.Sleep(5000); - SW.WriteLine("y"); - Thread.Sleep(5000); - SW.WriteLine("src/main/main.js"); - Thread.Sleep(5000); - SW.WriteLine("n"); - Thread.Sleep(5000); + + public static async Task StartImport(StreamWriter sw) + { + //part two of installation + await Task.Delay(5000); + await sw.WriteLineAsync("y"); + await Task.Delay(5000); + await sw.WriteLineAsync("y"); + await Task.Delay(5000); + await sw.WriteLineAsync("src/main/main.js"); + await Task.Delay(5000); + await sw.WriteLineAsync("n"); + await Task.Delay(5000); } - public static void StartModify(StreamWriter SW, string VERSION, string workDirectory = null, RichTextBox richTextBox1 = null) { //part three of installation + + public static async Task StartModify(StreamWriter sw, string workDirectory = null) + { + //part three of installation if (workDirectory == null) workDirectory = Directory.GetCurrentDirectory(); - SW.WriteLine("npm install electron-prebuilt-compile@4.0.0 --save-dev --save-exact"); - SW.WriteLine("cd .."); - SW.WriteLine("rd /s /q .\\temp\\.cache"); - SW.WriteLine("mkdir .\\temp\\resources\\auger\\replays"); - SW.WriteLine("robocopy /E /NP /MT .\\src .\\temp\\resources\\auger\\replays"); + await sw.WriteLineAsync("npm install electron-prebuilt-compile@4.0.0 --save-dev --save-exact"); + await sw.WriteLineAsync("cd .."); + await sw.WriteLineAsync("rd /s /q .\\temp\\.cache"); + await sw.WriteLineAsync("mkdir .\\temp\\resources\\auger\\replays"); + await sw.WriteLineAsync("robocopy /E /NP /MT .\\src .\\temp\\resources\\auger\\replays"); //-------------------------------------- //start modifying original plays files //-------------------------------------- //copying replaceables - SW.WriteLine("robocopy /E /NP /MT .\\src-patch\\src .\\temp\\src"); + await sw.WriteLineAsync("robocopy /E /NP /MT .\\src-patch\\src .\\temp\\src"); //set version - ModifyFileAtLine("log.info(`Version: " + VERSION + "`);", workDirectory + "\\temp\\src\\main\\main.js", 36, richTextBox1); - - int counter = 1; - string line; - StreamReader configFile = new StreamReader(workDirectory + "\\src-patch\\config.txt"); - while ((line = configFile.ReadLine()) != null) { - if (!line.StartsWith("#") && !String.IsNullOrEmpty(line)) { // if it is not a comment - if(line.StartsWith("ModifyFileAtLine") || line.StartsWith("AppendToFileAtLine")) { - string command = "ModifyFileAtLine"; - if (line.StartsWith("AppendToFileAtLine")) - command = "AppendToFileAtLine"; - - string fileName = line.Split(new string[] { "\"" }, 3, StringSplitOptions.None)[1]; - string lineNumber = line.Replace(command + " \"" + fileName + "\" ", ""); lineNumber = lineNumber.Substring(0, lineNumber.IndexOf(' ')); - string newLine = line.Replace(command + " \"" + fileName + "\" " + lineNumber + " ", ""); - - if(lineNumber.Contains("-") && command == "ModifyFileAtLine") { - int start = Int32.Parse(lineNumber.Split('-')[0]); - int end = Int32.Parse(lineNumber.Split('-')[1]); - - for (int i = start; i <= end; i++) { - ModifyFileAtLine(newLine, workDirectory + "\\temp" + fileName, i, richTextBox1); - counter++; - } - } else { - if(command == "AppendToFileAtLine") - AppendToFileAtLine(newLine, workDirectory + "\\temp" + fileName, Int32.Parse(lineNumber), richTextBox1); - else - ModifyFileAtLine(newLine, workDirectory + "\\temp" + fileName, Int32.Parse(lineNumber), richTextBox1); + await ModifyFileAtLineAsync( + "log.info(`Version: " + InstallerSettings.GetInstallerSetting(InstallerSetting.Version) + "`);", + workDirectory + "\\temp\\src\\main\\main.js", 36); + + var counter = 1; + using (var configFileReader = new StreamReader(workDirectory + "\\src-patch\\config.txt")) + { + while (!configFileReader.EndOfStream) + { + var readLine = await configFileReader.ReadLineAsync(); + if (readLine.StartsWith("#") || string.IsNullOrWhiteSpace(readLine)) + { + continue; // if it is not a comment + } + + if (!readLine.StartsWith("ModifyFileAtLine") && !readLine.StartsWith("AppendToFileAtLine")) + { + continue; + } + + var command = "ModifyFileAtLine"; + if (readLine.StartsWith("AppendToFileAtLine")) + { + command = "AppendToFileAtLine"; + } + + var fileName = readLine.Split(new[] {"\""}, 3, StringSplitOptions.None)[1]; + var lineNumber = readLine.Replace(command + " \"" + fileName + "\" ", ""); + lineNumber = lineNumber.Substring(0, lineNumber.IndexOf(' ')); + var newLine = readLine.Replace(command + " \"" + fileName + "\" " + lineNumber + " ", ""); + + if (lineNumber.Contains("-") && command == "ModifyFileAtLine") + { + var start = int.Parse(lineNumber.Split('-')[0]); + var end = int.Parse(lineNumber.Split('-')[1]); + + for (var i = start; i <= end; i++) + { + await ModifyFileAtLineAsync(newLine, workDirectory + "\\temp" + fileName, i); counter++; } } + else + { + if (command == "AppendToFileAtLine") + await AppendToFileAtLine(newLine, workDirectory + "\\temp" + fileName, + int.Parse(lineNumber)); + else + await ModifyFileAtLineAsync(newLine, workDirectory + "\\temp" + fileName, + int.Parse(lineNumber)); + counter++; + } } + + Main.Log("Number of changes: " + counter); } - Log("Number of changes: " + counter, richTextBox1); - configFile.Close(); - StartPackage(SW, VERSION, workDirectory); + await StartPackage(sw, workDirectory); } - public static void StartPackage(StreamWriter SW, string VERSION, string workDirectory = null) { //part four of installation - ModifyFileAtLine("" + VERSION + "-full", workDirectory + "\\Plays.nuspec", 5); - SW.WriteLine("copy /Y nuget.exe temp"); - SW.WriteLine("copy /Y Plays.nuspec temp"); - SW.WriteLine("cd temp"); - SW.WriteLine("npm run package"); - SW.WriteLine("robocopy /E /NP /MT ..\\PlaysSetup\\Plays-3.0.0-full\\lib\\net45\\resources\\ltc .\\out\\Plays-win32-ia32\\resources\\ltc"); - SW.WriteLine("rename .\\out\\Plays-win32-ia32 net45"); - SW.WriteLine("nuget.exe pack"); - StartInstall(SW, VERSION, workDirectory); + private static async Task StartPackage(TextWriter textWriter, string workDirectory = null) + { + //part four of installation + await ModifyFileAtLineAsync( + $"{InstallerSettings.GetInstallerSetting(InstallerSetting.Version)}-full", + workDirectory + "\\Plays.nuspec", 5); + await textWriter.WriteLineAsync("copy /Y nuget.exe temp"); + await textWriter.WriteLineAsync("copy /Y Plays.nuspec temp"); + await textWriter.WriteLineAsync("cd temp"); + await textWriter.WriteLineAsync("npm run package"); + await textWriter.WriteLineAsync( + "robocopy /E /NP /MT ..\\PlaysSetup\\Plays-3.0.0-full\\lib\\net45\\resources\\ltc .\\out\\Plays-win32-ia32\\resources\\ltc"); + await textWriter.WriteLineAsync("rename .\\out\\Plays-win32-ia32 net45"); + await textWriter.WriteLineAsync("nuget.exe pack"); + await StartInstallAsync(textWriter, workDirectory); } - public static void StartInstall(StreamWriter SW, string VERSION, string workDirectory = null) { //part five of installation - SW.WriteLine("copy /Y Plays." + VERSION + "-full.nupkg .."); - SW.WriteLine("cd .."); - SW.WriteLine("del /f RELEASES"); - if (workDirectory == rePlaysDirectory) { - SW.WriteLine("Update.exe --install=.\\"); - } else { - SW.WriteLine("echo WARNING: Current work directory is '" + workDirectory + "', proper work directory should be at '" + rePlaysDirectory + "', skipping completion install..."); + private static async Task StartInstallAsync(TextWriter textWriter, string workDirectory = null) + { + //part five of installation + await textWriter.WriteLineAsync("copy /Y Plays." + + InstallerSettings.GetInstallerSetting(InstallerSetting.Version) + + "-full.nupkg .."); + await textWriter.WriteLineAsync("cd .."); + await textWriter.WriteLineAsync("del /f RELEASES"); + + if (workDirectory == InstallerSettings.GetInstallerSetting(InstallerSetting.RePlaysDirectory)) + { + await textWriter.WriteLineAsync("Update.exe --install=.\\"); } - if((bool)installSettings["deleteTemp"] == true) { - SW.WriteLine("rd /s /q temp"); + else + { + await textWriter.WriteLineAsync( + $"echo WARNING: Current work directory is '{workDirectory}', proper work directory should be at '{InstallerSettings.GetInstallerSetting(InstallerSetting.RePlaysDirectory)}', skipping completion install..."); + } + + if (InstallerSettings.GetInstallerSetting(InstallerSetting.DeleteTemp)) + { + await textWriter.WriteLineAsync("rd /s /q temp"); } - SW.WriteLine("exit"); - } - public static void ModifyFileAtLine(string newText, string fileName, int line_to_edit, RichTextBox richTextBox1 = null) { - string[] arrLine = File.ReadAllLines(fileName); - arrLine[line_to_edit - 1] = newText; - File.WriteAllLines(fileName, arrLine); - Log(fileName + ">>> Writing to line " + line_to_edit + ": " + newText, richTextBox1); + await textWriter.WriteLineAsync("exit"); } - public static void AppendToFileAtLine(string newText, string fileName, int line_to_edit, RichTextBox richTextBox1 = null) { - var arrLine = File.ReadAllLines(fileName).ToList(); - arrLine.Insert(line_to_edit + 1, newText); - File.WriteAllLines(fileName, arrLine); - Log(fileName + ">>> Writing to line " + line_to_edit + ": " + newText, richTextBox1); + private static async Task ModifyFileAtLineAsync(string newText, string fileName, int lineToEdit) + { + var allTextFromFile = await AsynchronousFileHelper.ReadAllLinesAsync(fileName); + allTextFromFile[lineToEdit - 1] = newText; + await AsynchronousFileHelper.WriteAllLinesAsync(fileName, allTextFromFile); + Main.Log($"{fileName}>>> Writing to line {lineToEdit}: {newText}"); } - public static void Log(string msg, RichTextBox richTextBox1 = null) { - if (richTextBox1 != null) { - richTextBox1.AppendText(Environment.NewLine + "[" + DateTime.Now.ToString("h:mm:ss tt") + "] " + msg); - } Console.WriteLine(msg); + private static async Task AppendToFileAtLine(string newText, string fileName, int lineToEdit) + { + var allTextFromFile = (await AsynchronousFileHelper.ReadAllLinesAsync(fileName)).ToList(); + var arrLine = File.ReadAllLines(fileName).ToList(); + arrLine.Insert(lineToEdit + 1, newText); + await AsynchronousFileHelper.WriteAllLinesAsync(fileName, allTextFromFile); + Main.Log($"{fileName}>>> Writing to line {lineToEdit}: {newText}"); } } -} +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Main.cs b/installer/RePlaysTV-Installer/Main.cs deleted file mode 100644 index dcbf891..0000000 --- a/installer/RePlaysTV-Installer/Main.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Windows.Forms; - -namespace RePlaysTV_Installer { - public partial class Main : Form { - public string VERSION; - - public static Process p; - public static StreamWriter SW; - public static Main mainForm; - public static Options optionsForm = new Options(); - public Main(string _VERSION) { - VERSION = _VERSION; - - InitializeComponent(); - mainForm = this; - } - private void Main_Load(object sender, EventArgs e) { - mainForm.Text = "RePlaysTV " + VERSION + " Installer"; - mainForm.WindowState = FormWindowState.Minimized; - mainForm.Show(); - mainForm.WindowState = FormWindowState.Normal; - - p = new Process(); - - p.StartInfo.FileName = "cmd.exe"; - p.StartInfo.UseShellExecute = false; - p.StartInfo.CreateNoWindow = true; - p.StartInfo.RedirectStandardInput = true; - p.StartInfo.RedirectStandardOutput = true; - p.StartInfo.RedirectStandardError = true; - p.StartInfo.StandardOutputEncoding = Encoding.UTF8; - p.StartInfo.StandardErrorEncoding = Encoding.UTF8; - - p.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler); - p.ErrorDataReceived += new DataReceivedEventHandler(SortOutputHandler); - - p.Start(); - - SW = p.StandardInput; - SW.WriteLine("chcp 65001"); //set encoding - - p.BeginOutputReadLine(); - p.BeginErrorReadLine(); - } - - private async void Button1_Click(object sender, EventArgs e) { - mainForm.TopMost = true; - DialogResult dr1 = MessageBox.Show("This automated process can take up to 10 minutes or more.\n" + - "Please have at least ~1.5GB of disk space available." + - "\nPress Yes to start install.", "RePlaysTV Installer", MessageBoxButtons.YesNoCancel,MessageBoxIcon.Information); - if (dr1 == DialogResult.Yes) { - await Installer.DownloadSetup(mainForm.richTextBox1); - Installer.ListInstalledAntivirusProducts(mainForm.richTextBox1); - Installer.StartExtract(SW); - } - mainForm.TopMost = false; - } - - private void Button2_Click(object sender, EventArgs e) { - optionsForm.ShowDialog(); - } - - private void Button3_Click(object sender, EventArgs e) { - Clipboard.SetText(mainForm.richTextBox1.Text); - } - private void InstallComplete() { - mainForm.TopMost = true; - MessageBox.Show("Installation Complete!", "RePlaysTV Installer", MessageBoxButtons.OK, MessageBoxIcon.Information); - mainForm.TopMost = false; - } - private static bool startImport = false; - private static void SortOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { - if (!String.IsNullOrEmpty(outLine.Data)) { - if (mainForm.richTextBox1.InvokeRequired) { - mainForm.richTextBox1.Invoke(new MethodInvoker(delegate { - if (outLine.Data.Contains("All rights reserved.")) { - mainForm.richTextBox1.Text = "[" + DateTime.Now.ToString("h:mm:ss tt") + "] Ready"; - } else if (outLine.Data.Contains("We will now attempt to import: ") && !startImport) { //part two of installation - var enterThread = new Thread( - new ThreadStart( - () => { - Installer.StartImport(SW); - mainForm.Invoke(new MethodInvoker(delegate { - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "[" + DateTime.Now.ToString("h:mm:ss tt") + "] This next process will take awhile (with no sign of progress)... Please be patient."); - })); - } - )); - startImport = true; - enterThread.Start(); - } else { - if (outLine.Data.Contains("npm install") || (outLine.Data.Contains("electron-forge package") && !outLine.Data.Contains("\"electron-forge package\"")) || outLine.Data.Contains("asar extract")) { - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "[" + DateTime.Now.ToString("h:mm:ss tt") + "] This next process will take awhile (with no sign of progress)... Please be patient."); - } - if (outLine.Data.Contains("Thanks for using ") && outLine.Data.Contains("electron-forge")) { - Installer.StartModify(SW, mainForm.VERSION, null, mainForm.richTextBox1); - } - if (outLine.Data.Contains("npm ERR!") || outLine.Data.Contains("unhandled error") || outLine.Data.Contains("Error: ")) { - mainForm.TopMost = true; - System.Windows.Forms.MessageBox.Show("An unhandled error has occurred during the install, It is possible that the installation has failed.\nTry restarting your computer and turn off anti-virus before installing.\n\nReport this issue by copying the logs and sending it to a developer."); - mainForm.TopMost = false; - } - if (outLine.Data.Contains("'nodejs-portable.exe' is not recognized")) { - mainForm.TopMost = true; - System.Windows.Forms.MessageBox.Show("'nodejs-portable.exe' is missing from the working directory.\n\nMake sure you properly extracted the installer to a folder."); - mainForm.TopMost = false; - } - if (outLine.Data.Contains(">exit")) { - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "======================================="); - mainForm.richTextBox1.AppendText(Environment.NewLine + "[" + DateTime.Now.ToString("h:mm:ss tt") + "] Installation Complete!"); - mainForm.Invoke(new MethodInvoker(delegate { mainForm.InstallComplete(); })); - } - mainForm.richTextBox1.AppendText(Environment.NewLine + "[" + DateTime.Now.ToString("h:mm:ss tt") + "] " + outLine.Data.ToString()); - } - })); - } - } - } - - private void Main_FormClosing(object sender, FormClosingEventArgs e) { - p.Kill(); - } - - private void LinkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - Process.Start("https://github.com/lulzsun/RePlaysTV"); - } - } -} diff --git a/installer/RePlaysTV-Installer/MainProgram.cs b/installer/RePlaysTV-Installer/MainProgram.cs new file mode 100644 index 0000000..942716f --- /dev/null +++ b/installer/RePlaysTV-Installer/MainProgram.cs @@ -0,0 +1,121 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using RePlaysTV_Installer.Settings; +using RePlaysTV_Installer.Views; + +namespace RePlaysTV_Installer +{ + internal static class MainProgram + { + [STAThread] + private static async Task Main(string[] args) + { + ActivateGlobalExceptionHandling(); + InstallerSettings.SetInstallerSetting(InstallerSetting.Version, Application.ProductVersion); + + if (args.Length == 0) + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Main()); + return; + } + + var workDirectory = args[0]; //args[0] - working dir passed from replays client + using (var commandLineProcess = new CommandLineProcess(workDirectory)) + { + commandLineProcess.StartCommandLineProcess(); + commandLineProcess.SetupStreamWriterWithEncoding(); + + await Task.Factory.StartNew(commandLineProcess.ExecuteMainTaskAsync); + } + } + + private static void ActivateGlobalExceptionHandling() + { + // Add the event handler for handling UI thread exceptions to the event. + Application.ThreadException += UIThreadException; + + // Set the unhandled exception mode to force all Windows Forms errors to go through + // our handler. + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); + + // Add the event handler for handling non-UI thread exceptions to the event. + AppDomain.CurrentDomain.UnhandledException += UnhandledException; + } + + + // Handle the UI exceptions by showing a dialog box, and asking the user whether + // or not they wish to abort execution. + private static void UIThreadException(object sender, ThreadExceptionEventArgs t) + { + var result = DialogResult.Cancel; + try + { + result = ShowThreadExceptionDialog("Windows Forms Error", t.Exception); + } + catch + { + try + { + MessageBox.Show("Fatal Windows Forms Error", "Fatal Windows Forms Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop); + } + finally + { + Application.Exit(); + } + } + + // Exits the program when the user clicks Abort. + if (result == DialogResult.Abort) + { + Application.Exit(); + } + } + + // Handle the UI exceptions by showing a dialog box, and asking the user whether + // or not they wish to abort execution. + // NOTE: This exception cannot be kept from terminating the application - it can only + // log the event, and inform the user about it. + private static void UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + try + { + var ex = (Exception)e.ExceptionObject; + var errorMessage = $"An application error occurred. Please contact the adminstrator with the following information:{Environment.NewLine}{Environment.NewLine}"; + + // Since we can't prevent the app from terminating, log this to the event log. + if (!EventLog.SourceExists("ThreadException")) + { + EventLog.CreateEventSource("ThreadException", "Application"); + } + + // Create an EventLog instance and assign its source. + var myLog = new EventLog { Source = "ThreadException" }; + myLog.WriteEntry($"{errorMessage}{ex.Message}{Environment.NewLine}{Environment.NewLine}Stack Trace:{Environment.NewLine}{ex.StackTrace}"); + } + catch (Exception) + { + try + { + MessageBox.Show("Fatal Non-UI Error. Could not write the error to the event log. Reason: {exc.Message}", "Fatal Non-UI Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); + } + finally + { + Application.Exit(); + } + } + } + + // Creates the error message and displays it. + private static DialogResult ShowThreadExceptionDialog(string title, Exception e) + { + var errorMsg = $"An application error occurred. Please contact the adminstrator with the following information:{Environment.NewLine}{Environment.NewLine}"; + errorMsg = $"{errorMsg}{e.Message}{Environment.NewLine}{Environment.NewLine}Stack Trace:{Environment.NewLine}{e.StackTrace}"; + return MessageBox.Show(errorMsg, title, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop); + } + } +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Options.cs b/installer/RePlaysTV-Installer/Options.cs deleted file mode 100644 index d8809b2..0000000 --- a/installer/RePlaysTV-Installer/Options.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace RePlaysTV_Installer { - public partial class Options : Form { - public Options() { - InitializeComponent(); - } - - private void Options_FormClosing(object sender, FormClosingEventArgs e) { - this.Hide(); - e.Cancel = true; - } - - private void Options_Load(object sender, EventArgs e) { - playsSetupUrl.Text = (string)Installer.installSettings["playsSetupUrl"]; - ltcVersion.Text = (string)Installer.installSettings["ltcVersion"]; - cleanInstall.Checked = (bool)Installer.installSettings["cleanInstall"]; - deleteTemp.Checked = (bool)Installer.installSettings["deleteTemp"]; - ignoreChecksum.Checked = (bool)Installer.installSettings["ignoreChecksum"]; - } - - private void Button5_Click(object sender, EventArgs e) { - Installer.installSettings = new Dictionary() - { - { "playsSetupUrl", playsSetupUrl.Text }, - { "ltcVersion", ltcVersion.Text }, - { "cleanInstall", cleanInstall.Checked }, - { "deleteTemp", deleteTemp.Checked }, - { "ignoreChecksum", ignoreChecksum.Checked }, - }; - } - - private void Button1_Click(object sender, EventArgs e) { - Process.Start(Directory.GetCurrentDirectory()); - } - - private void Button2_Click(object sender, EventArgs e) { - Process.Start(Environment.GetEnvironmentVariable("LocalAppData") + "\\Plays"); - } - - private void Button3_Click(object sender, EventArgs e) { - Process.Start(Environment.GetEnvironmentVariable("LocalAppData") + "\\Plays-ltc"); - } - - private void Button4_Click(object sender, EventArgs e) { - Process.Start(Environment.GetEnvironmentVariable("AppData") + "\\Plays"); - } - - private void Button6_Click(object sender, EventArgs e) { - DialogResult dr1 = MessageBox.Show("Are you sure you want to uninstall Plays?", - "RePlaysTV Installer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); - if (dr1 == DialogResult.Yes) { - Process.Start("cmd.exe", "/C \"" + Environment.GetEnvironmentVariable("LocalAppData") + "\\Plays\\Update.exe\" --uninstall &&" + - "rd /s /q \"" + Environment.GetEnvironmentVariable("LocalAppData") + "\\Plays\" &&" + - "rd /s /q \"" + Environment.GetEnvironmentVariable("LocalAppData") + "\\Plays-ltc\""); - } - } - - private void Button8_Click(object sender, EventArgs e) { - DialogResult dr1 = MessageBox.Show("Are you sure you want to uninstall the RePlays Installer?\n" + - "This will not uninstall Plays or RePlays patched Plays.", - "RePlaysTV Installer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); - if (dr1 == DialogResult.Yes) { - - } - } - - private void Button7_Click(object sender, EventArgs e) { - DialogResult dr1 = MessageBox.Show("Are you sure you want to uninstall Yarn?\n" + - "This will uninstall Yarn from your local version of npm if it is installed globally.", - "RePlaysTV Installer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); - if (dr1 == DialogResult.Yes) { - - } - } - } -} diff --git a/installer/RePlaysTV-Installer/Properties/AssemblyInfo.cs b/installer/RePlaysTV-Installer/Properties/AssemblyInfo.cs index 12b34d5..091ac4a 100644 --- a/installer/RePlaysTV-Installer/Properties/AssemblyInfo.cs +++ b/installer/RePlaysTV-Installer/Properties/AssemblyInfo.cs @@ -1,7 +1,10 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +#region + +using System.Reflection; using System.Runtime.InteropServices; +#endregion + // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. @@ -32,5 +35,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("3.0.4.0")] +[assembly: AssemblyFileVersion("3.0.4.0")] \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Properties/Settings.settings b/installer/RePlaysTV-Installer/Properties/Settings.settings index 3964565..e04fc63 100644 --- a/installer/RePlaysTV-Installer/Properties/Settings.settings +++ b/installer/RePlaysTV-Installer/Properties/Settings.settings @@ -1,7 +1,8 @@  + - + \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/RePlaysTV-Installer.csproj b/installer/RePlaysTV-Installer/RePlaysTV-Installer.csproj index 9fdbd4d..6d201ec 100644 --- a/installer/RePlaysTV-Installer/RePlaysTV-Installer.csproj +++ b/installer/RePlaysTV-Installer/RePlaysTV-Installer.csproj @@ -48,25 +48,29 @@ - + + + + + Form - + Main.cs - + Form - + Options.cs - + - + Main.cs - + Options.cs @@ -90,5 +94,6 @@ True + \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Settings/InstallerSetting.cs b/installer/RePlaysTV-Installer/Settings/InstallerSetting.cs new file mode 100644 index 0000000..9c4ad89 --- /dev/null +++ b/installer/RePlaysTV-Installer/Settings/InstallerSetting.cs @@ -0,0 +1,15 @@ +namespace RePlaysTV_Installer.Settings +{ + internal enum InstallerSetting + { + PlaysSetupUrl, + CorrectPlaysSetupHash, + LtcVersion, + CleanInstall, + DeleteTemp, + IgnoreChecksum, + RePlaysDirectory, + Version, + PlaySetupExecutableSizeInBytes + } +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Settings/InstallerSettings.cs b/installer/RePlaysTV-Installer/Settings/InstallerSettings.cs new file mode 100644 index 0000000..815d8ad --- /dev/null +++ b/installer/RePlaysTV-Installer/Settings/InstallerSettings.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +namespace RePlaysTV_Installer.Settings +{ + internal static class InstallerSettings + { + private static readonly Dictionary InstallSettings = + new Dictionary + { + { + InstallerSetting.PlaysSetupUrl, + "https://web.archive.org/web/20191212211927if_/https://app-updates.plays.tv/builds/PlaysSetup.exe" + }, + {InstallerSetting.LtcVersion, "0.54.7"}, + {InstallerSetting.CleanInstall, true}, + {InstallerSetting.DeleteTemp, false}, + {InstallerSetting.IgnoreChecksum, false}, + {InstallerSetting.Version, ""}, + {InstallerSetting.RePlaysDirectory, $"{Environment.GetEnvironmentVariable("LocalAppData")}\\RePlays"}, + {InstallerSetting.CorrectPlaysSetupHash, "3a7cea84d50ad2c31a79e66f5c3f3b8d"}, + {InstallerSetting.PlaySetupExecutableSizeInBytes, 145310344M} + }; + + public static T GetInstallerSetting(string settingIdentifier) + { + if (string.IsNullOrWhiteSpace(settingIdentifier) || + !Enum.TryParse(settingIdentifier, out var installerSetting)) + throw new ArgumentNullException(nameof(settingIdentifier)); + + return GetInstallerSetting(installerSetting); + } + + public static T GetInstallerSetting(InstallerSetting installerSetting) + { + return (T) (InstallSettings.TryGetValue(installerSetting, out var result) ? result : null); + } + + public static bool RemoveInstallerSetting(string settingIdentifier) + { + if (string.IsNullOrWhiteSpace(settingIdentifier) || + !Enum.TryParse(settingIdentifier, out var installerSetting)) + throw new ArgumentNullException(nameof(settingIdentifier)); + + return RemoveInstallerSetting(installerSetting); + } + + public static bool RemoveInstallerSetting(InstallerSetting installerSetting) + { + return InstallSettings.Remove(installerSetting); + } + + public static void SetInstallerSetting(string settingIdentifier, object value) + { + if (string.IsNullOrWhiteSpace(settingIdentifier) + || value == null + || !Enum.TryParse(settingIdentifier, out var installerSetting)) + throw new ArgumentNullException(nameof(settingIdentifier)); + + SetInstallerSetting(installerSetting, value); + } + + public static void SetInstallerSetting(InstallerSetting installerSetting, object value) + { + if (value == null || InstallSettings == null || + GetInstallerSetting(installerSetting).Equals(value)) + { + return; + } + + InstallSettings[installerSetting] = value; + } + } +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Main.Designer.cs b/installer/RePlaysTV-Installer/Views/Main.Designer.cs similarity index 90% rename from installer/RePlaysTV-Installer/Main.Designer.cs rename to installer/RePlaysTV-Installer/Views/Main.Designer.cs index 9967972..52302fc 100644 --- a/installer/RePlaysTV-Installer/Main.Designer.cs +++ b/installer/RePlaysTV-Installer/Views/Main.Designer.cs @@ -1,21 +1,10 @@ -namespace RePlaysTV_Installer { +namespace RePlaysTV_Installer.Views { partial class Main { /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) { - if (disposing && (components != null)) { - components.Dispose(); - } - base.Dispose(disposing); - } - #region Windows Form Designer generated code /// @@ -114,8 +103,6 @@ private void InitializeComponent() { this.Name = "Main"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "RePlaysTV Installer"; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing); - this.Load += new System.EventHandler(this.Main_Load); this.ResumeLayout(false); this.PerformLayout(); diff --git a/installer/RePlaysTV-Installer/Views/Main.cs b/installer/RePlaysTV-Installer/Views/Main.cs new file mode 100644 index 0000000..1a1370f --- /dev/null +++ b/installer/RePlaysTV-Installer/Views/Main.cs @@ -0,0 +1,157 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using System.Windows.Forms; +using RePlaysTV_Installer.Settings; + +namespace RePlaysTV_Installer.Views +{ + public partial class Main : Form + { + private static Main _mainForm; + private static readonly Options OptionsForm = new Options(); + private CommandLineProcess _mainCommandLineProcess; + + public Main() + { + InitializeComponent(); + Load += OnLoad; + FormClosing += OnFormClosing; + _mainForm = this; + } + + private void OnLoad(object sender, EventArgs e) + { + _mainForm.Text = + $"RePlaysTV {InstallerSettings.GetInstallerSetting(InstallerSetting.Version)} Installer"; + _mainForm.WindowState = FormWindowState.Minimized; + _mainForm.Show(); + _mainForm.WindowState = FormWindowState.Normal; + + _mainCommandLineProcess = new CommandLineProcess(null); + _mainCommandLineProcess.StartCommandLineProcess(); + _mainCommandLineProcess.SetupStreamWriterWithEncoding(); + } + + private async void Button1_Click(object sender, EventArgs e) + { + _mainForm.TopMost = true; + var dr1 = MessageBox.Show("This automated Process can take up to 10 minutes or more.\n" + + "Please have at least ~1.5GB of disk space available." + + "\nPress Yes to start install.", "RePlaysTV Installer", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); + if (dr1 != DialogResult.Yes) + { + _mainForm.TopMost = false; + return; + } + + await Task.Factory.StartNew(_mainCommandLineProcess.ExecuteMainTaskAsync); + } + + public static void Log(string msg) + { + if (string.IsNullOrWhiteSpace(msg)) + { + return; + } + + if (_mainForm != null) + { + _mainForm.AppendToLogTextBox($"[{DateTime.Now:h: mm:ss tt}]{msg}"); + return; + } + + Console.WriteLine($"[{DateTime.Now:h: mm:ss tt}]{msg}"); + } + + private void AppendToLogTextBox(string value) + { + if (InvokeRequired) + { + Invoke(new Action(AppendToLogTextBox), value); + return; + } + + richTextBox1.AppendText($"{Environment.NewLine}{value}"); + } + + private void Button2_Click(object sender, EventArgs e) + { + OptionsForm.ShowDialog(this); + } + + private void Button3_Click(object sender, EventArgs e) + { + Clipboard.SetText(_mainForm.richTextBox1.Text); + } + + public static void InstallComplete() + { + ShowMessageBox("Installation Complete!", "RePlaysTV Installer"); + } + + public static void ShowMessageBox( + string message, + string caption = null, + MessageBoxButtons messageBoxButtons = MessageBoxButtons.OK, + MessageBoxIcon messageBoxIcon = MessageBoxIcon.Information) + { + if (string.IsNullOrWhiteSpace(message)) + { + return; + } + + if (_mainForm != null) + { + _mainForm.ShowMessageBox(message, messageBoxButtons, messageBoxIcon, caption); + return; + } + + Console.WriteLine(message); + } + + private void ShowMessageBox( + string message, + MessageBoxButtons messageBoxButtons, + MessageBoxIcon messageBoxIcon, + string caption) + { + if (InvokeRequired) + { + Invoke(new Action(ShowMessageBox), message, + messageBoxButtons, messageBoxIcon, caption); + return; + } + + _mainForm.TopMost = true; + MessageBox.Show(message, caption, messageBoxButtons, messageBoxIcon); + _mainForm.TopMost = false; + } + + private void OnFormClosing(object sender, FormClosingEventArgs e) + { + _mainCommandLineProcess.Dispose(); + Application.Exit(); + } + + private void LinkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start("https://github.com/lulzsun/RePlaysTV"); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + if (components != null) + { + components?.Dispose(); + _mainCommandLineProcess?.Dispose(); + } + + // Dispose stuff here + + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Main.resx b/installer/RePlaysTV-Installer/Views/Main.resx similarity index 100% rename from installer/RePlaysTV-Installer/Main.resx rename to installer/RePlaysTV-Installer/Views/Main.resx diff --git a/installer/RePlaysTV-Installer/Options.Designer.cs b/installer/RePlaysTV-Installer/Views/Options.Designer.cs similarity index 96% rename from installer/RePlaysTV-Installer/Options.Designer.cs rename to installer/RePlaysTV-Installer/Views/Options.Designer.cs index d83c6cb..ceeb566 100644 --- a/installer/RePlaysTV-Installer/Options.Designer.cs +++ b/installer/RePlaysTV-Installer/Views/Options.Designer.cs @@ -1,21 +1,10 @@ -namespace RePlaysTV_Installer { +namespace RePlaysTV_Installer.Views { partial class Options { /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) { - if (disposing && (components != null)) { - components.Dispose(); - } - base.Dispose(disposing); - } - #region Windows Form Designer generated code /// @@ -297,7 +286,7 @@ private void InitializeComponent() { this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Options"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Options_FormClosing); - this.Load += new System.EventHandler(this.Options_Load); + this.Load += new System.EventHandler(this.LoadOptions); this.groupBox1.ResumeLayout(false); this.groupBox2.ResumeLayout(false); this.groupBox3.ResumeLayout(false); diff --git a/installer/RePlaysTV-Installer/Views/Options.cs b/installer/RePlaysTV-Installer/Views/Options.cs new file mode 100644 index 0000000..897bf57 --- /dev/null +++ b/installer/RePlaysTV-Installer/Views/Options.cs @@ -0,0 +1,103 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Windows.Forms; +using RePlaysTV_Installer.Settings; + +namespace RePlaysTV_Installer.Views +{ + public partial class Options : Form + { + public Options() + { + InitializeComponent(); + } + + private void Options_FormClosing(object sender, FormClosingEventArgs e) + { + Hide(); + e.Cancel = true; + } + + private void LoadOptions(object sender, EventArgs e) + { + playsSetupUrl.Text = InstallerSettings.GetInstallerSetting(InstallerSetting.PlaysSetupUrl); + ltcVersion.Text = InstallerSettings.GetInstallerSetting(InstallerSetting.LtcVersion); + cleanInstall.Checked = InstallerSettings.GetInstallerSetting(InstallerSetting.CleanInstall); + deleteTemp.Checked = InstallerSettings.GetInstallerSetting(InstallerSetting.DeleteTemp); + ignoreChecksum.Checked = InstallerSettings.GetInstallerSetting(InstallerSetting.IgnoreChecksum); + } + + private void Button5_Click(object sender, EventArgs e) + { + InstallerSettings.SetInstallerSetting(InstallerSetting.PlaysSetupUrl, playsSetupUrl.Text); + InstallerSettings.SetInstallerSetting(InstallerSetting.LtcVersion, ltcVersion.Text); + InstallerSettings.SetInstallerSetting(InstallerSetting.CleanInstall, cleanInstall.Checked); + InstallerSettings.SetInstallerSetting(InstallerSetting.DeleteTemp, deleteTemp.Checked); + InstallerSettings.SetInstallerSetting(InstallerSetting.IgnoreChecksum, ignoreChecksum.Checked); + } + + private void Button1_Click(object sender, EventArgs e) + { + Process.Start(Directory.GetCurrentDirectory()); + } + + private void Button2_Click(object sender, EventArgs e) + { + Process.Start(Environment.GetEnvironmentVariable("LocalAppData") + "\\Plays"); + } + + private void Button3_Click(object sender, EventArgs e) + { + Process.Start(Environment.GetEnvironmentVariable("LocalAppData") + "\\Plays-ltc"); + } + + private void Button4_Click(object sender, EventArgs e) + { + Process.Start(Environment.GetEnvironmentVariable("AppData") + "\\Plays"); + } + + private void Button6_Click(object sender, EventArgs e) + { + var dr1 = MessageBox.Show("Are you sure you want to uninstall Plays?", + "RePlaysTV Installer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); + if (dr1 == DialogResult.Yes) + Process.Start("cmd.exe", "/C \"" + Environment.GetEnvironmentVariable("LocalAppData") + + "\\Plays\\Update.exe\" --uninstall &&" + + "rd /s /q \"" + Environment.GetEnvironmentVariable("LocalAppData") + + "\\Plays\" &&" + + "rd /s /q \"" + Environment.GetEnvironmentVariable("LocalAppData") + + "\\Plays-ltc\""); + } + + private void Button8_Click(object sender, EventArgs e) + { + var dr1 = MessageBox.Show("Are you sure you want to uninstall the RePlays Installer?\n" + + "This will not uninstall Plays or RePlays patched Plays.", + "RePlaysTV Installer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); + if (dr1 == DialogResult.Yes) + { + } + } + + private void Button7_Click(object sender, EventArgs e) + { + var dr1 = MessageBox.Show("Are you sure you want to uninstall Yarn?\n" + + "This will uninstall Yarn from your local version of npm if it is installed globally.", + "RePlaysTV Installer", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); + if (dr1 == DialogResult.Yes) + { + } + } + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && components != null) components.Dispose(); + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/installer/RePlaysTV-Installer/Options.resx b/installer/RePlaysTV-Installer/Views/Options.resx similarity index 100% rename from installer/RePlaysTV-Installer/Options.resx rename to installer/RePlaysTV-Installer/Views/Options.resx diff --git a/installer/RePlaysTV-Installer/app.config b/installer/RePlaysTV-Installer/app.config index 51278a4..8de7ab2 100644 --- a/installer/RePlaysTV-Installer/app.config +++ b/installer/RePlaysTV-Installer/app.config @@ -1,3 +1,7 @@ + - + + + + \ No newline at end of file