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 00000000..3e07dd1e
Binary files /dev/null and b/src/ARKServerManager/Art/Restart.ico differ
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 00000000..3e07dd1e
Binary files /dev/null and b/src/ConanServerManager/Art/Restart.ico differ
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 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
-
+
@@ -544,7 +664,7 @@
-
+
diff --git a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs b/src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs
index 9554a83d..b2ee9381 100644
--- a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs
+++ b/src/ConanServerManager/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,19 +29,41 @@ 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)
+ 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.LatestServerManagerBetaVersionUrl : Config.Default.LatestServerManagerVersionUrl;
@@ -813,5 +875,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;
+ }
+ }
}
}