From 3f4cc944b77448fa819567d97720da20dad410e7 Mon Sep 17 00:00:00 2001 From: Brett Hewitson Date: Tue, 17 May 2022 00:31:26 +1000 Subject: [PATCH] Server Monitor Changes - added Start, Stop, Restart, Update and Backup buttons and functionality. --- src/ARKServerManager/ARKServerManager.csproj | 1 + src/ARKServerManager/Art/Restart.ico | Bin 0 -> 102134 bytes .../Globalization/en-US/en-US.xaml | 24 +- .../Windows/ServerMonitorWindow.xaml | 144 ++++- .../Windows/ServerMonitorWindow.xaml.cs | 568 +++++++++++++++++ src/ConanServerManager/Art/Restart.ico | Bin 0 -> 102134 bytes .../ConanServerManager.csproj | 1 + .../Globalization/en-US/en-US.xaml | 24 +- .../Windows/ServerMonitorWindow.xaml | 136 ++++- .../Windows/ServerMonitorWindow.xaml.cs | 570 +++++++++++++++++- 10 files changed, 1445 insertions(+), 23 deletions(-) create mode 100644 src/ARKServerManager/Art/Restart.ico create mode 100644 src/ConanServerManager/Art/Restart.ico diff --git a/src/ARKServerManager/ARKServerManager.csproj b/src/ARKServerManager/ARKServerManager.csproj index 22b8ccaa..b505318f 100644 --- a/src/ARKServerManager/ARKServerManager.csproj +++ b/src/ARKServerManager/ARKServerManager.csproj @@ -366,6 +366,7 @@ + Always diff --git a/src/ARKServerManager/Art/Restart.ico b/src/ARKServerManager/Art/Restart.ico new file mode 100644 index 0000000000000000000000000000000000000000..3e07dd1e5dbac768eff7c468250f8e9dd1477596 GIT binary patch literal 102134 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 literal 0 HcmV?d00001 diff --git a/src/ARKServerManager/Globalization/en-US/en-US.xaml b/src/ARKServerManager/Globalization/en-US/en-US.xaml index dc7d809c..c2a65f54 100644 --- a/src/ARKServerManager/Globalization/en-US/en-US.xaml +++ b/src/ARKServerManager/Globalization/en-US/en-US.xaml @@ -440,6 +440,7 @@ Server Monitor + Selected Total Servers: Server Map @@ -449,6 +450,13 @@ Status Create a desktop shortcut to open this form directly. + Start the selected servers. + Stop the selected servers. + Restart the selected servers. + Update the selected servers. + Backup the selected servers. + Select all servers. + Unselect all servers. Open the Player List window. Open the RCON window. Start the server. @@ -459,7 +467,21 @@ Server Update Error Another server is being upgraded, wait until the upgrade has finished and try again. Confirm Window Close - You are currently perform a server update, closing the window with disconnect you from steamcmd. Do you want to continue closing the window? + You are currently performing a server update, closing the window will disconnect you from steamcmd. Do you want to continue closing the window? + Confirm Start Servers + You are about to start the selected servers. Do you want to continue? + Confirm Stop Servers + You are about to stop the selected servers. Do you want to continue? + Confirm Restart Servers + You are about to restart the selected servers. Do you want to continue? + Confirm Update Servers + You are about to update the selected servers. Do you want to continue? + Confirm Backup Servers + You are about to backup the selected servers. Do you want to continue? + Selected Servers Error + You have not selected any servers. Selected one or more servers in the list and try again. + Close Server Monitor Error + The server monitor window cannot be closed at this time. One or more of the servers is currently starting, shutting down or restarting. diff --git a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml index d2791ff9..95ff243c 100644 --- a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml +++ b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml @@ -4,6 +4,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:tb="http://www.hardcodet.net/taskbar" + xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" + xmlns:sm="clr-namespace:ServerManagerTool" + xmlns:smw="clr-namespace:ServerManagerTool.Windows" xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common" xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common" xmlns:enum="clr-namespace:ServerManagerTool.Enums" @@ -18,21 +21,31 @@ - + + - + - + + + - + + + + + + + + @@ -41,12 +54,95 @@ - + + + + + + + + + + + + + + + - - + + + + - + @@ -544,7 +664,7 @@ - + @@ -557,7 +677,7 @@ Visibility="{Binding IsStandAloneWindow, Converter={StaticResource BooleanToVisibilityConverter}}" ToolTipText="{Binding Title}" IconSource="../Art/favicon.ico" - LeftClickCommand="{Binding ShowWindowCommand, ElementName=ServerMonitorUI}"> + LeftClickCommand="{Binding ShowWindowCommand, ElementName=ServerMonitorUI}" Grid.ColumnSpan="2"> diff --git a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs index f23ac64e..34dd543b 100644 --- a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs +++ b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs @@ -2,6 +2,7 @@ using NLog; using ServerManagerTool.Common.Lib; using ServerManagerTool.Common.Utils; +using ServerManagerTool.DiscordBot.Enums; using ServerManagerTool.Enums; using ServerManagerTool.Lib; using ServerManagerTool.Plugin.Common; @@ -16,7 +17,9 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Documents; using System.Windows.Input; +using System.Windows.Media; using WPFSharp.Globalizer; namespace ServerManagerTool.Windows @@ -26,17 +29,39 @@ namespace ServerManagerTool.Windows /// public partial class ServerMonitorWindow : Window { + public class ServerMonitorOutput_Error : Run + { + public ServerMonitorOutput_Error(string value) + : base(value) + { + Foreground = Brushes.Red; + } + } + + public class ServerMonitorOutput_Success : Run + { + public ServerMonitorOutput_Success(string value) + : base(value) + { + Foreground = Brushes.Green; + } + } + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly List Windows = new List(); private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance; private CancellationTokenSource _upgradeCancellationSource = null; private ActionQueue _versionChecker; + private readonly Dictionary _currentProfileCommands = new Dictionary(); + + private bool HasRunningCommands => _currentProfileCommands.Count > 0; public static readonly DependencyProperty ServerManagerProperty = DependencyProperty.Register(nameof(ServerManager), typeof(ServerManager), typeof(ServerMonitorWindow), new PropertyMetadata(null)); public static readonly DependencyProperty LatestServerManagerVersionProperty = DependencyProperty.Register(nameof(LatestServerManagerVersion), typeof(Version), typeof(ServerMonitorWindow), new PropertyMetadata(new Version())); public static readonly DependencyProperty ShowUpdateButtonProperty = DependencyProperty.Register(nameof(ShowUpdateButton), typeof(bool), typeof(ServerMonitorWindow), new PropertyMetadata(false)); public static readonly DependencyProperty IsStandAloneWindowProperty = DependencyProperty.Register(nameof(IsStandAloneWindow), typeof(bool), typeof(ServerMonitorWindow), new PropertyMetadata(false)); + public static readonly DependencyProperty CancellationTokenSourceProperty = DependencyProperty.Register(nameof(CancellationTokenSource), typeof(CancellationTokenSource), typeof(ServerMonitorWindow)); public ServerMonitorWindow() : this(null) { @@ -89,6 +114,12 @@ namespace ServerManagerTool.Windows set { SetValue(IsStandAloneWindowProperty, value); } } + public CancellationTokenSource CancellationTokenSource + { + get { return (CancellationTokenSource)GetValue(CancellationTokenSourceProperty); } + set { SetValue(CancellationTokenSourceProperty, value); } + } + private void ServerMonitorWindow_Loaded(object sender, RoutedEventArgs e) { if (ServerManager == null) @@ -156,6 +187,14 @@ namespace ServerManagerTool.Windows protected override void OnClosing(CancelEventArgs e) { + if (HasRunningCommands) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_RunningProcesses_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_RunningProcesses_ConfirmTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + + e.Cancel = true; + return; + } + if (this.OwnedWindows.OfType().Any()) { if (MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_CloseWindow_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_CloseWindow_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes) @@ -409,6 +448,29 @@ namespace ServerManagerTool.Windows } } + public void AddErrorBlockContent(string message) + { + var p = new Paragraph(); + + p.Inlines.Add(new ServerMonitorOutput_Error(message)); + + ConsoleContent.Blocks.Add(p); + } + + public void AddMessageBlockContent(string message) + { + var p = new Paragraph(); + + p.Inlines.Add(new ServerMonitorOutput_Success(message)); + + ConsoleContent.Blocks.Add(p); + } + + public void ClearBlockContents() + { + ConsoleContent.Blocks.Clear(); + } + private async Task CheckForUpdates() { string url = App.Instance.BetaVersion ? Config.Default.LatestASMBetaVersionUrl : Config.Default.LatestASMVersionUrl; @@ -816,5 +878,511 @@ namespace ServerManagerTool.Windows } #endregion + + private async void BackupServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_BackupServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_BackupServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Backup); + profileList.Add(ServerProfileSnapshot.Create(server.Profile)); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Backup, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileBackup(profile, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void RestartServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_RestartServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_RestartServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Restart); + var profile = ServerProfileSnapshot.Create(server.Profile); + profile.AutoRestartIfShutdown = true; + profileList.Add(profile); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Restart, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, true, false, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_RestartRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void StartServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_StartServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_StartServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Running: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Start); + var profile = ServerProfileSnapshot.Create(server.Profile); + profile.AutoRestartIfShutdown = true; + profileList.Add(profile); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Restart, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, true, false, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_StartRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void StopServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_StopServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_StopServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Stopped: + case ServerStatus.Uninstalled: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Stop); + profileList.Add(ServerProfileSnapshot.Create(server.Profile)); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Shutdown, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, false, false, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ShutdownRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private async void UpdateServers_Click(object sender, RoutedEventArgs e) + { + if (CancellationTokenSource != null) + return; + + var serverList = ServerManager.Servers.Where(s => s.Selected); + if (serverList.IsEmpty()) + { + MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorLabel"), _globalizer.GetResourceString("ServerMonitor_NoServersSelected_ErrorTitle"), MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var result = MessageBox.Show(_globalizer.GetResourceString("ServerMonitor_UpdateServers_ConfirmLabel"), _globalizer.GetResourceString("ServerMonitor_UpdateServers_ConfirmTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result != MessageBoxResult.Yes) + return; + + ClearBlockContents(); + + var profileList = new List(); + + foreach (var server in serverList) + { + var performRestart = false; + + // check if another command is being run against the profile + if (_currentProfileCommands.ContainsKey(server.Profile.ProfileID)) + { + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[server.Profile.ProfileID], server.Profile.ProfileName)); + continue; + } + + switch (server.Runtime.Status) + { + case ServerStatus.Running: + performRestart = true; + break; + + case ServerStatus.Initializing: + case ServerStatus.Stopping: + case ServerStatus.Unknown: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), server.Profile.ProfileName, server.Runtime.StatusString)); + continue; + + case ServerStatus.Updating: + AddErrorBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), server.Profile.ProfileName)); + continue; + } + + _currentProfileCommands.Add(server.Profile.ProfileID, CommandType.Update); + var profile = ServerProfileSnapshot.Create(server.Profile); + profile.RestartAfterShutdown1 = performRestart; // use this property to trigger a restart + profileList.Add(profile); + } + + CancellationTokenSource = new CancellationTokenSource(); + var token = CancellationTokenSource.Token; + var tasks = new List(); + + foreach (var profile in profileList) + { + var app = new ServerApp(true) + { + DeleteOldBackupFiles = !Config.Default.AutoBackup_EnableBackup, + OutputLogs = false, + SendAlerts = true, + SendEmails = false, + ServerProcess = ServerProcessType.Update, + ServerStatusChangeCallback = (ServerStatus serverStatus) => + { + TaskUtils.RunOnUIThreadAsync(() => + { + var server = ServerManager.Instance.Servers.FirstOrDefault(s => string.Equals(profile.ProfileId, s.Profile.ProfileID, StringComparison.OrdinalIgnoreCase)); + if (server != null) + { + server.Runtime.UpdateServerStatus(serverStatus, serverStatus != ServerStatus.Unknown); + } + }).Wait(token); + } + }; + + var task = Task.Run(() => + { + app.PerformProfileShutdown(profile, profile.RestartAfterShutdown1, true, false, false, token); + _currentProfileCommands.Remove(profile.ProfileId); + }, token); + + tasks.Add(task); + + AddMessageBlockContent(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName)); + } + + try + { + await Task.WhenAll(tasks); + } + catch { } + finally + { + CancellationTokenSource?.Dispose(); + CancellationTokenSource = null; + } + } + + private void SelectAllServers_Click(object sender, RoutedEventArgs e) + { + foreach (var server in ServerManager.Servers) + { + server.Selected = true; + } + } + + private void UnselectAllServers_Click(object sender, RoutedEventArgs e) + { + foreach (var server in ServerManager.Servers) + { + server.Selected = false; + } + } } } diff --git a/src/ConanServerManager/Art/Restart.ico b/src/ConanServerManager/Art/Restart.ico new file mode 100644 index 0000000000000000000000000000000000000000..3e07dd1e5dbac768eff7c468250f8e9dd1477596 GIT binary patch literal 102134 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 literal 0 HcmV?d00001 diff --git a/src/ConanServerManager/ConanServerManager.csproj b/src/ConanServerManager/ConanServerManager.csproj index 467f0588..e1053835 100644 --- a/src/ConanServerManager/ConanServerManager.csproj +++ b/src/ConanServerManager/ConanServerManager.csproj @@ -297,6 +297,7 @@ + Designer PreserveNewest diff --git a/src/ConanServerManager/Globalization/en-US/en-US.xaml b/src/ConanServerManager/Globalization/en-US/en-US.xaml index 36c7d163..a55a7174 100644 --- a/src/ConanServerManager/Globalization/en-US/en-US.xaml +++ b/src/ConanServerManager/Globalization/en-US/en-US.xaml @@ -400,6 +400,7 @@ Server Monitor + Selected Total Servers: Server Map @@ -409,6 +410,13 @@ Status Create a desktop shortcut to open this form directly. + Start the selected servers. + Stop the selected servers. + Restart the selected servers. + Update the selected servers. + Backup the selected servers. + Select all servers. + Unselect all servers. Open the Player List window. Open the RCON window. Start the server. @@ -419,7 +427,21 @@ Server Update Error Another server is being upgraded, wait until the upgrade has finished and try again. Confirm Window Close - You are currently perform a server update, closing the window with disconnect you from steamcmd. Do you want to continue closing the window? + You are currently performing a server update, closing the window will disconnect you from steamcmd. Do you want to continue closing the window? + Confirm Start Servers + You are about to start the selected servers. Do you want to continue? + Confirm Stop Servers + You are about to stop the selected servers. Do you want to continue? + Confirm Restart Servers + You are about to restart the selected servers. Do you want to continue? + Confirm Update Servers + You are about to update the selected servers. Do you want to continue? + Confirm Backup Servers + You are about to backup the selected servers. Do you want to continue? + Selected Servers Error + You have not selected any servers. Selected one or more servers in the list and try again. + Close Server Monitor Error + The server monitor window cannot be closed at this time. One or more of the servers is currently starting, shutting down or restarting. diff --git a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml b/src/ConanServerManager/Windows/ServerMonitorWindow.xaml index 8d28adf1..9c8b12f6 100644 --- a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml +++ b/src/ConanServerManager/Windows/ServerMonitorWindow.xaml @@ -4,6 +4,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:tb="http://www.hardcodet.net/taskbar" + xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" + xmlns:sm="clr-namespace:ServerManagerTool" + xmlns:smw="clr-namespace:ServerManagerTool.Windows" xmlns:clib="clr-namespace:ServerManagerTool.Common.Lib;assembly=ServerManager.Common" xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common" xmlns:enum="clr-namespace:ServerManagerTool.Enums" @@ -19,6 +22,7 @@ + @@ -28,11 +32,20 @@ - + + + - + + + + + + + + @@ -41,12 +54,95 @@ - + + + + + + + + + + + + + + + -