示例#1
0
        private bool CheckWrapperSettings()
        {
            try
            {
                if (!Directory.Exists(@"Wrapper\Settings.json"))
                {
                    ProcessStartInfo psi = new ProcessStartInfo()
                    {
                        CreateNoWindow = false,
                        UseShellExecute = false,
                        FileName = @"MCServerWrapperSettingsApp.exe",
                        WindowStyle = ProcessWindowStyle.Normal,
                    };

                    using (Process settingsApp = Process.Start(psi))
                    {
                        settingsApp.WaitForExit();
                    }
                }

                if (File.Exists(@"Wrapper\Settings.json"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, $"Error launching {@"MCServerWrapperSettingsApp.exe"}");
                return false;
            }
        }
示例#2
0
 private void CleanUp()
 {
     Stopwatch sw = new Stopwatch();
     try
     {
         sw.Start();
         while (backups.Count > settings.BackupNumber)
         {
             string backup;
             int counter = 0;
             while (!backups.TryDequeue(out backup))
             {
                 counter++;
                 if (counter > 19)
                 {
                     throw new Exception("Failed to dequeue the oldest backup for deletion after 20 tries.");
                 }
             }
             File.Delete(backup);
         }
         sw.Stop();
         ConsoleWriter.WriteLine("Removed extra backups in " + sw.ElapsedMilliseconds + " ms", consoleColor);
     }
     catch (Exception ex)
     {
         sw.Stop();
         ExceptionPrinter.PrintException(ex, "Failed to remove extra backups.");
     }
 }
示例#3
0
        private bool SaveSettings(Settings settings)
        {
            try
            {
                if (File.Exists(@"Wrapper\Settings.json"))
                {
                    File.Delete(@"Wrapper\Settings.json");
                }
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error deleting old Settings.json while generating new Settings.json");
                return false;
            }

            try
            {
                string json = JsonConvert.SerializeObject(settings, Formatting.Indented);
                File.WriteAllText(@"Wrapper\Settings.json", json);
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error creating Settings.json while generating new Settings.json");
                return false;
            }

            ConsoleWriter.WriteLine("Successfully found the backup source automatically", consoleColor);
            return true;
        }
示例#4
0
        private bool Backup(out Exception exception)
        {
            Stopwatch sw = new Stopwatch();

            //The name of the backup zip file. Not the full path only the file name
            string zipName = $"{DateTime.Now.Year}-{DateTime.Now.Month}-{DateTime.Now.Day}_{DateTime.Now.Hour}-{DateTime.Now.Minute}-{DateTime.Now.Second}.zip";

            //Begins Backup
            try
            {
                sw.Start();
                using (FileStream fs = File.Create(Path.Combine(settings.BackupLocation, zipName)))
                {
                    fs.CompressZip(settings.BackupSource, settings.ZipCompressionLevel, true);
                }
                sw.Stop();
                ConsoleWriter.WriteLine("Created backup in " + sw.ElapsedMilliseconds + " ms", consoleColor);
            }
            catch (Exception ex)
            {
                sw.Stop();
                if (File.Exists(Path.Combine(settings.BackupLocation, zipName)))
                {
                    File.Delete(Path.Combine(settings.BackupLocation, zipName));
                }
                exception = ex;
                return false;
            }

            //Enqueues the new backup into settings for saving
            backups.Enqueue(Path.Combine(settings.BackupLocation, zipName));

            //Removes excess backups
            CleanUp();

            //save new backuplist queue to BackupList.json
            try
            {
                string json = JsonConvert.SerializeObject(backups.ToArray(), Formatting.Indented);
                File.WriteAllText(@"Wrapper\BackupList.json", json);
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error writing backups to BackupList.json");
            }

            //cleanUp.Wait();
            exception = null;
            return true;
        }
示例#5
0
        private void AutoFindBackupSource()
        {
            if (Directory.Exists(Path.Combine(Environment.CurrentDirectory, "world")))
            {
                try
                {
                    Settings newSettings = new Settings()
                    {
                        AutoFindBackupSource = false,
                        BackupInterval = settings.BackupInterval,
                        BackupLocation = settings.BackupLocation,
                        BackupNumber = settings.BackupNumber,
                        BackupSource = Path.Combine(Environment.CurrentDirectory, "world"),
                        LaunchFlags = settings.LaunchFlags,
                        MaxRam = settings.MaxRam,
                        MinRam = settings.MinRam,
                        SameMaxMin = settings.SameMaxMin,
                        ServerPath = settings.ServerPath,
                        ShowCpuRamUsage = settings.ShowCpuRamUsage,
                        WrapperColor = settings.WrapperColor,
                        ZipCompressionLevel = settings.ZipCompressionLevel,
                    };

                    if (stopping)
                        return;

                    int counter = 0;
                    while (!SaveSettings(newSettings) && counter < 9)
                    {
                        counter++;

                        if (stopping)
                            return;

                        if (counter >= 9)
                        {
                            throw new Exception("Failed to update Settings.json after 10 tries");
                        }
                    }

                    string json = File.ReadAllText(@"Wrapper\Settings.json");
                    settings = JsonConvert.DeserializeObject<Settings>(json);
                }
                catch (Exception ex)
                {
                    ExceptionPrinter.PrintException(ex);
                }
            }
        }
示例#6
0
 private void Close(int exitCode)
 {
     try
     {
         if (process != null && !process.HasExited)
         {
             process.StandardInput.WriteLine("stop");
             process.WaitForExit();
         }
     }
     catch (Exception ex)
     {
         ExceptionPrinter.PrintException(ex, "Failed to exit process");
     }
     Thread.Sleep(2000);
     ConsoleWriter.WriteLine("Press Enter key to continue...", consoleColor);
     Console.ReadLine();
     Environment.Exit(exitCode);
 }
示例#7
0
        public ServerProgram()
        {
            stopping = false;

            handler = new ConsoleEventDelegate((eventType) =>
            {
                if (eventType == 2)
                {
                    ConsoleWriter.WriteLine("Caught closing", consoleColor);
                    if (!process.HasExited)
                    {
                        process.StandardInput.WriteLine("stop");
                        process.WaitForExit();
                    }
                }
                return false;
            });

            SetConsoleCtrlHandler(handler, true);

            //Sets event that attempts to close the server when the wrapper application closes unexpecedly
            AppDomain.CurrentDomain.DomainUnload += (s, e) =>
            {
                try
                {
                    if (!process.HasExited || process != null)
                        process.StandardInput.Write("stop");
                }
                catch { }
            };

            //Checks for Wrapper dir and creates it if it doesn't exist
            try
            {
                if (!Directory.Exists(@"Wrapper"))
                    Directory.CreateDirectory(@"Wrapper");
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error creating wrapper directory.");
                Close(10);
                return;
            }

            //Checks for BackupList.json and creates one if it doesn't exist
            try
            {
                if (!File.Exists(@"Wrapper\BackupList.json"))
                {
                    JsonSerializerSettings jsonSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto };
                    string json = JsonConvert.SerializeObject(new ConcurrentQueue<string>().ToArray(), Formatting.Indented, jsonSettings);
                    File.WriteAllText(@"Wrapper\BackupList.json", json);
                }
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error creating new BackupsList.json");
                Close(10);
                return;
            }

            //Checks for BackupList.json and reads info from it
            try
            {
                if (File.Exists(@"Wrapper\BackupList.json"))
                {
                    JsonSerializerSettings jsonSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto };
                    string json = File.ReadAllText(@"Wrapper\BackupList.json");
                    backups = new ConcurrentQueue<string>(JsonConvert.DeserializeObject<string[]>(json, jsonSettings));
                }
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error reading data from BackupList.json");
                Close(10);
                return;
            }

            //Checks for Settings.json and creates one if not found
            try
            {
                if (!File.Exists(@"Wrapper\Settings.json"))
                {
                    int counter = 0;
                    while (!CheckWrapperSettings() && counter < 4)
                    {
                        counter++;
                    }

                    if (counter >= 4)
                    {
                        throw new Exception("Unable to create Settings.json after 5 tries");
                    }
                }

                string json = File.ReadAllText(@"Wrapper\Settings.json");
                settings = JsonConvert.DeserializeObject<Settings>(json);
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error reading Settings.json");
                Close(10);
                return;
            }

            //sets the color the wrapper text specific to the wrapper
            consoleColor = settings.WrapperColor;

            //Checks if the server application and server wrapper are in the same directory
            try
            {
                if (Environment.CurrentDirectory != Path.GetDirectoryName(settings.ServerPath))
                {
                    ExceptionPrinter.PrintException(new Exception("Server application is not in the same directory as the wrapper.\nPlease put the server wrapper in the same directory as the server file."));
                    Close(10);
                    return;
                }
            }
            catch (Exception ex)
            {
                ExceptionPrinter.PrintException(ex, "Error checking server path and wrapper path");
                Close(10);
                return;
            }

            Console.Title = Path.GetFileName(settings.ServerPath);

            //initialize and fill lists
            float[] filler = new float[LIST_MAX];

            for (int i = 0; i < filler.Length; i++)
                filler[i] = 0;

            ProcessorTimeList = new List<float>(filler);
            PrivilegedTimeList = new List<float>(filler);
            UserTimeList = new List<float>(filler);
            WorkingSetPrivateList = new List<float>(filler);
            WorkingSetPeakList = new List<float>(filler);
            WorkingSetList = new List<float>(filler);
            IOReadList = new List<float>(filler);
            IOWriteList = new List<float>(filler);
            IODataList = new List<float>(filler);
            IOOtherList = new List<float>(filler);
            PageFileList = new List<float>(filler);
            PageFilePeakList = new List<float>(filler);
            VirtualList = new List<float>(filler);
            VirtualPeakList = new List<float>(filler);
            PoolPagedList = new List<float>(filler);
            PoolNonpagedList = new List<float>(filler);

            //Timer Instatiation
            BackupTimer = new Timer(settings.BackupInterval * 60000);
            FormUpdateTimer = new Timer(1000);

            //maximize console
            ShowWindow(Process.GetCurrentProcess().MainWindowHandle, 3);
        }
示例#8
0
        public void Start()
        {
            //Writes starting info to the console
            ConsoleWriter.WriteLine($"Starting", consoleColor);
            ConsoleWriter.WriteLine($"Program Source {settings.ServerPath}", consoleColor);
            ConsoleWriter.WriteLine($"Min RAM: {settings.MinRam}MB", consoleColor);
            ConsoleWriter.WriteLine($"Max RAM: {settings.MaxRam}MB", consoleColor);
            ConsoleWriter.WriteLine($"Backup Interval: {settings.BackupInterval} minutes", consoleColor);
            ConsoleWriter.WriteLine($"Number of Backups: {settings.BackupNumber}", consoleColor);
            ConsoleWriter.WriteLine($"Backup Compression Level: {settings.ZipCompressionLevel}", consoleColor);
            ConsoleWriter.WriteLine($"Backup Source: {settings.BackupSource}", consoleColor);
            ConsoleWriter.WriteLine($"Backup Destination: {settings.BackupLocation}", consoleColor);
            ConsoleWriter.WriteLine($"Show CPU and RAM Usage: {settings.ShowCpuRamUsage}", consoleColor);
            ConsoleWriter.WriteLine($"Launch Flags: {settings.LaunchFlags}", consoleColor);

            //initializes the process
            process = new Process();
            process.StartInfo = new ProcessStartInfo("java", $"-Xms{settings.MinRam}M -Xmx{settings.MaxRam}M {settings.LaunchFlags} -jar {settings.ServerPath} nogui")
            {
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardError = true,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
            };

            //Set Backup Timer
            BackupTimer.Elapsed += (s, e) =>
            {
                if (process.HasExited || process == null)
                    return;

                try
                {
                    process.StandardInput.WriteLine("save-off");
                    process.StandardInput.WriteLine("say Starting Backup. Server may lag for a bit.");
                    Exception exception;
                    int counter = 0;
                    while (!Backup(out exception))
                    {
                        counter++;
                        if (counter > 19)
                        {
                            throw new Exception("Unable to complete backup after 20 tries", exception);
                        }
                    }
                    process.StandardInput.WriteLine($"say Backup Successful. Next backup in {settings.BackupInterval} minutes");
                }
                catch (Exception ex)
                {
                    process.StandardInput.WriteLine($"say Backup Failed. {ex.Message}.");
                    ExceptionPrinter.PrintException(ex, "Error while trying to initialize backup.");
                    CleanUp();
                }
                try { process.StandardInput.WriteLine("save-on"); } catch (Exception ex) { ExceptionPrinter.PrintException(ex, "Failed to send \"save-on\" message"); }
            };

            //Set FormUpdateTimer
            FormUpdateTimer.Elapsed += (s, e) =>
            {
                if (process.HasExited)
                    return;

                try
                {
                    //gets newest data
                    float privilegedTime = PrivilegedTime.NextValue();
                    float processorTime = ProcessorTime.NextValue();
                    float userTime = UserTime.NextValue();
                    float creatingProcessID = CreatingProcessID.NextValue();
                    float elapsedTime = ElapsedTime.NextValue();
                    float handleCount = HandleCount.NextValue();
                    float idProcess = IDProcess.NextValue();
                    float ioDataBytes = IODataBytes.NextValue();
                    float ioOtherBytes = IOOtherBytes.NextValue();
                    float ioReadBytes = IOReadBytes.NextValue();
                    float ioWriteBytes = IOWriteBytes.NextValue();
                    float pageFaults = PageFaults.NextValue();
                    float pageFileBytes = PageFileBytes.NextValue();
                    float pageFileBytesPeak = PageFileBytesPeak.NextValue();
                    float poolNonpagedBytes = PoolNonpagedBytes.NextValue();
                    float poolPagedBytes = PoolPagedBytes.NextValue();
                    float priorityBase = PriorityBase.NextValue();
                    float privateBytes = PrivateBytes.NextValue();
                    float threadCount = ThreadCount.NextValue();
                    float virtualBytes = VirtualBytes.NextValue();
                    float virtualBytesPeak = VirtualBytesPeak.NextValue();
                    float workingSet = WorkingSet.NextValue();
                    float workingSetPrivate = WorkingSetPrivate.NextValue();
                    float workingSetPeak = WorkingSetPeak.NextValue();

                    //adds newest data to the lists
                    ProcessorTimeList.Insert(0, processorTime / Environment.ProcessorCount / 100f);
                    PrivilegedTimeList.Insert(0, privilegedTime / Environment.ProcessorCount / 100f);
                    UserTimeList.Insert(0, userTime / Environment.ProcessorCount / 100f);
                    WorkingSetPrivateList.Insert(0, workingSetPrivate / 1048576);
                    WorkingSetPeakList.Insert(0, workingSetPeak / 1048576);
                    WorkingSetList.Insert(0, workingSet / 1048576);
                    IOReadList.Insert(0, ioReadBytes / 1024);
                    IOWriteList.Insert(0, ioWriteBytes / 1024);
                    IODataList.Insert(0, ioDataBytes / 1024);
                    IOOtherList.Insert(0, ioOtherBytes / 1024);
                    WorkingSetPrivateList.Insert(0, workingSetPrivate / 1048576);
                    WorkingSetPeakList.Insert(0, workingSetPeak / 1048576);
                    WorkingSetList.Insert(0, workingSet / 1048576);
                    PageFileList.Insert(0, pageFileBytes / 1048576);
                    PageFilePeakList.Insert(0, pageFileBytesPeak / 1048576);
                    VirtualList.Insert(0, virtualBytes / 1048576);
                    VirtualPeakList.Insert(0, virtualBytesPeak / 1048576);
                    PoolPagedList.Insert(0, poolPagedBytes / 1024);
                    PoolNonpagedList.Insert(0, poolNonpagedBytes / 1024);

                    //sorten lists to max size
                    while (ProcessorTimeList.Count > LIST_MAX)
                        ProcessorTimeList.RemoveAt(LIST_MAX);
                    while (PrivilegedTimeList.Count > LIST_MAX)
                        PrivilegedTimeList.RemoveAt(LIST_MAX);
                    while (UserTimeList.Count > LIST_MAX)
                        UserTimeList.RemoveAt(LIST_MAX);
                    while (WorkingSetPrivateList.Count > LIST_MAX)
                        WorkingSetPrivateList.RemoveAt(LIST_MAX);
                    while (WorkingSetPeakList.Count > LIST_MAX)
                        WorkingSetPeakList.RemoveAt(LIST_MAX);
                    while (WorkingSetList.Count > LIST_MAX)
                        WorkingSetList.RemoveAt(LIST_MAX);
                    while (IOReadList.Count > LIST_MAX)
                        IOReadList.RemoveAt(LIST_MAX);
                    while (IOWriteList.Count > LIST_MAX)
                        IOWriteList.RemoveAt(LIST_MAX);
                    while (IODataList.Count > LIST_MAX)
                        IODataList.RemoveAt(LIST_MAX);
                    while (IOOtherList.Count > LIST_MAX)
                        IOOtherList.RemoveAt(LIST_MAX);
                    while (WorkingSetPrivateList.Count > LIST_MAX)
                        WorkingSetPrivateList.RemoveAt(LIST_MAX);
                    while (WorkingSetPeakList.Count > LIST_MAX)
                        WorkingSetPeakList.RemoveAt(LIST_MAX);
                    while (WorkingSetList.Count > LIST_MAX)
                        WorkingSetList.RemoveAt(LIST_MAX);
                    while (PageFileList.Count > LIST_MAX)
                        PageFileList.RemoveAt(LIST_MAX);
                    while (PageFilePeakList.Count > LIST_MAX)
                        PageFilePeakList.RemoveAt(LIST_MAX);
                    while (VirtualList.Count > LIST_MAX)
                        VirtualList.RemoveAt(LIST_MAX);
                    while (VirtualPeakList.Count > LIST_MAX)
                        VirtualPeakList.RemoveAt(LIST_MAX);
                    while (PoolPagedList.Count > LIST_MAX)
                        PoolPagedList.RemoveAt(LIST_MAX);
                    while (PoolNonpagedList.Count > LIST_MAX)
                        PoolNonpagedList.RemoveAt(LIST_MAX);

                    if (processInfoForm.IsDisposed)
                        return;

                    //pass info to form
                    processInfoForm.UpdateOverviewCPU(ProcessorTimeList.ToArray(), PrivilegedTimeList.ToArray(), UserTimeList.ToArray());
                    processInfoForm.UpdateOverviewMemory(WorkingSetPrivateList.ToArray(), WorkingSetPeakList.ToArray(), WorkingSetList.ToArray());
                    processInfoForm.UpdateOverviewIO(IOReadList.ToArray(), IOWriteList.ToArray());
                    processInfoForm.UpdateOverviewInfo(creatingProcessID, elapsedTime, handleCount, idProcess, pageFaults, priorityBase, privateBytes, threadCount);
                    processInfoForm.UpdateMemoryWorkingSet(WorkingSetPrivateList.ToArray(), WorkingSetPeakList.ToArray(), WorkingSetList.ToArray());
                    processInfoForm.UpdateMemoryPageFileList(PageFileList.ToArray(), PageFilePeakList.ToArray());
                    processInfoForm.UpdateMemoryVirtual(VirtualList.ToArray(), VirtualPeakList.ToArray());
                    processInfoForm.UpdateMemoryPool(PoolPagedList.ToArray(), PoolNonpagedList.ToArray());
                    processInfoForm.UpdateIOReadWrite(IOReadList.ToArray(), IOWriteList.ToArray());
                    processInfoForm.UpdateIODataOther(IODataList.ToArray(), IOOtherList.ToArray());
                }
                catch { }
            };

            //Form Thread
            Action FormStartupAction = new Action(() =>
            {
                processInfoForm = new ProcessInfoForm(LIST_MAX);
                FormUpdateTimer.Start();
                Application.Run(processInfoForm);
                FormUpdateTimer.Stop();
            });

            //load commands
            wrapperCommands = new List<Command>();

            wrapperCommands.Add(new Command("showstats", () =>
            {
                Task.Run(FormStartupAction);
            }));

            //pre-start backup
            if (!settings.AutoFindBackupSource)
            {
                try
                {
                    ConsoleWriter.WriteLine("Starting pre-start backup", consoleColor);
                    Exception exception;
                    int counter = 0;
                    while (!Backup(out exception))
                    {
                        counter++;
                        if (counter > 19)
                        {
                            throw new Exception("Unable to complete backup after 20 tries", exception);
                        }
                    }
                }
                catch (Exception ex)
                {
                    ExceptionPrinter.PrintException(ex, "Error while trying to initialize pre-start backup.");
                    CleanUp();
                }
            }

            //Starts the server process
            process.Start();

            //Performance Counter
            PrivilegedTime = new PerformanceCounter("Process", "% Privileged Time", process.ProcessName, true);
            ProcessorTime = new PerformanceCounter("Process", "% Processor Time", process.ProcessName, true);
            UserTime = new PerformanceCounter("Process", "% User Time", process.ProcessName, true);
            CreatingProcessID = new PerformanceCounter("Process", "Creating Process ID", process.ProcessName, true);
            ElapsedTime = new PerformanceCounter("Process", "Elapsed Time", process.ProcessName, true);
            HandleCount = new PerformanceCounter("Process", "Handle Count", process.ProcessName, true);
            IDProcess = new PerformanceCounter("Process", "ID Process", process.ProcessName, true);
            IODataBytes = new PerformanceCounter("Process", "IO Data Bytes/sec", process.ProcessName, true);
            IOOtherBytes = new PerformanceCounter("Process", "IO Other Bytes/sec", process.ProcessName, true);
            IOReadBytes = new PerformanceCounter("Process", "IO Read Bytes/sec", process.ProcessName, true);
            IOWriteBytes = new PerformanceCounter("Process", "IO Write Bytes/sec", process.ProcessName, true);
            PageFaults = new PerformanceCounter("Process", "Page Faults/sec", process.ProcessName, true);
            PageFileBytes = new PerformanceCounter("Process", "Page File Bytes", process.ProcessName, true);
            PageFileBytesPeak = new PerformanceCounter("Process", "Page File Bytes Peak", process.ProcessName, true);
            PoolNonpagedBytes = new PerformanceCounter("Process", "Pool Nonpaged Bytes", process.ProcessName, true);
            PoolPagedBytes = new PerformanceCounter("Process", "Pool Paged Bytes", process.ProcessName, true);
            PriorityBase = new PerformanceCounter("Process", "Priority Base", process.ProcessName, true);
            PrivateBytes = new PerformanceCounter("Process", "Private Bytes", process.ProcessName, true);
            ThreadCount = new PerformanceCounter("Process", "Thread Count", process.ProcessName, true);
            VirtualBytes = new PerformanceCounter("Process", "Virtual Bytes", process.ProcessName, true);
            VirtualBytesPeak = new PerformanceCounter("Process", "Virtual Bytes Peak", process.ProcessName, true);
            WorkingSet = new PerformanceCounter("Process", "Working Set", process.ProcessName, true);
            WorkingSetPrivate = new PerformanceCounter("Process", "Working Set - Private", process.ProcessName, true);
            WorkingSetPeak = new PerformanceCounter("Process", "Working Set Peak", process.ProcessName, true);

            //Set priority and initalize threads
            const ThreadPriority ioPriority = ThreadPriority.AboveNormal;
            Thread outputThread = new Thread(outputReader) { Name = "ChildIO Output", Priority = ioPriority, IsBackground = true };
            Thread errorThread = new Thread(errorReader) { Name = "ChildIO Error", Priority = ioPriority, IsBackground = true };
            Thread inputThread = new Thread(inputReader) { Name = "ChildIO Input", Priority = ioPriority, IsBackground = true };

            //Start the IO threads
            outputThread.Start(process);
            errorThread.Start(process);
            inputThread.Start(process);

            //Signal to end the application
            ManualResetEvent stopApp = new ManualResetEvent(false);

            //Enables the exited event and set the stopApp signal on exited
            process.EnableRaisingEvents = true;
            process.Exited += (e, sender) => { stopApp.Set(); };

            //BackupThread.Start();
            BackupTimer.Start();

            //starts server info form
            if (settings.ShowCpuRamUsage)
                Task.Run(FormStartupAction);

            //Thread.Sleep(10000);
            if (settings.AutoFindBackupSource)
            {
                //ConsoleWriter.WriteLine("Please wait until the post-start backup has finished before closing to prevent backup corruption", consoleColor);
                Task.Run(async () => 
                {
                    Thread.CurrentThread.Name = "AutoSource";
                    await Task.Delay(10000);
                    AutoFindBackupSource();

                    await Task.Delay(20000);

                    if (stopping)
                        return;

                    try
                    {
                        ConsoleWriter.WriteLine("Starting post-start backup", consoleColor);
                        process.StandardInput.WriteLine("save-off");
                        process.StandardInput.WriteLine("say Starting Backup. Server may lag for a bit.");
                        Exception exception;
                        int counter = 0;
                        while (!Backup(out exception))
                        {
                            counter++;
                            if (counter > 19)
                            {
                                throw new Exception("Unable to complete backup after 20 tries", exception);
                            }
                        }
                        process.StandardInput.WriteLine($"say Post-Start Backup Successful. Next backup in about {settings.BackupInterval - 1} minutes");
                    }
                    catch (Exception ex)
                    {
                        process.StandardInput.WriteLine($"say Backup Failed. {ex.Message}.");
                        ExceptionPrinter.PrintException(ex, "Error while trying to initialize backup.");
                        CleanUp();
                    }
                    try { process.StandardInput.WriteLine("save-on"); } catch (Exception ex) { ExceptionPrinter.PrintException(ex, "Failed to send \"save-on\" message"); }
                });
            }

            process.WaitForExit();
            stopApp.WaitOne();

            ConsoleWriter.WriteLine("Process ended... shutting down host", consoleColor);

            stopping = true;

            //stops timers
            BackupTimer.Stop();
            FormUpdateTimer.Stop();

            BackupTimer.Dispose();
            FormUpdateTimer.Dispose();

            //closes and disposes of the form
            if (processInfoForm != null && !processInfoForm.IsDisposed)
            {
                try
                {
                    if (processInfoForm.InvokeRequired)
                        processInfoForm.Invoke((MethodInvoker)(() => processInfoForm.Close()));
                    else
                        processInfoForm.Close();
                }
                catch { }
                finally
                {
                    if (!processInfoForm.IsDisposed)
                        if (processInfoForm.InvokeRequired)
                            processInfoForm.Invoke((MethodInvoker)(() => processInfoForm.Dispose()));
                        else
                            processInfoForm.Dispose();
                }
            }

            //disposes of performance counters
            PrivilegedTime.Dispose();
            ProcessorTime.Dispose();
            UserTime.Dispose();
            CreatingProcessID.Dispose();
            ElapsedTime.Dispose();
            HandleCount.Dispose();
            IDProcess.Dispose();
            IODataBytes.Dispose();
            IOOtherBytes.Dispose();
            IOReadBytes.Dispose();
            IOWriteBytes.Dispose();
            PageFaults.Dispose();
            PageFileBytes.Dispose();
            PageFileBytesPeak.Dispose();
            PoolNonpagedBytes.Dispose();
            PoolPagedBytes.Dispose();
            PriorityBase.Dispose();
            PrivateBytes.Dispose();
            ThreadCount.Dispose();
            VirtualBytes.Dispose();
            VirtualBytesPeak.Dispose();
            WorkingSet.Dispose();
            WorkingSetPrivate.Dispose();
            WorkingSetPeak.Dispose();

            if (outputThread.IsAlive)
                outputThread.Abort();

            if (errorThread.IsAlive)
                errorThread.Abort();

            if (inputThread.IsAlive)
                inputThread.Abort();

            ConsoleWriter.WriteLine("Press Enter to continue...", consoleColor);
            Console.ReadLine();
        }