diff --git a/src/ARKServerManager/ARKServerManager.csproj b/src/ARKServerManager/ARKServerManager.csproj
index 3d5408c4..908bfddf 100644
--- a/src/ARKServerManager/ARKServerManager.csproj
+++ b/src/ARKServerManager/ARKServerManager.csproj
@@ -173,6 +173,7 @@
MSBuild:Compile
Designer
+
@@ -196,7 +197,7 @@
-
+
diff --git a/src/ARKServerManager/Delegates/ServerStatusChangeDelegate.cs b/src/ARKServerManager/Delegates/ServerStatusChangeDelegate.cs
new file mode 100644
index 00000000..c7ab834a
--- /dev/null
+++ b/src/ARKServerManager/Delegates/ServerStatusChangeDelegate.cs
@@ -0,0 +1,6 @@
+using ServerManagerTool.Enums;
+
+namespace ServerManagerTool.Delegates
+{
+ public delegate void ServerStatusChangeDelegate(ServerStatus serverStatus);
+}
diff --git a/src/ARKServerManager/Enums/ServerProcessType.cs b/src/ARKServerManager/Enums/ServerProcessType.cs
index 861e2081..7298dfd9 100644
--- a/src/ARKServerManager/Enums/ServerProcessType.cs
+++ b/src/ARKServerManager/Enums/ServerProcessType.cs
@@ -10,5 +10,6 @@
Backup,
Shutdown,
Restart,
+ Update,
}
}
diff --git a/src/ARKServerManager/Globalization/en-US/en-US.xaml b/src/ARKServerManager/Globalization/en-US/en-US.xaml
index fd970206..3329e06d 100644
--- a/src/ARKServerManager/Globalization/en-US/en-US.xaml
+++ b/src/ARKServerManager/Globalization/en-US/en-US.xaml
@@ -786,6 +786,9 @@
Reinstall SteamCMD Error
An error occured while trying to reinstall SteamCMD. This has left SteamCmd in an unstable state, try reinstalling again or please report this.\r\nException: {0}
+ Discord Bot Running Commands
+ The discord bot has one or more running commands, do you want to continue shutting down the server manager?
+
Start Server Confirmation
You are about to start the server, do you want to continue?
Shutdown Server Confirmation
@@ -5547,12 +5550,17 @@
Command '{0}' has not been implemented.
Unknown command '{0}'.
- Another command is currently running.
-
- The command requires a profile id.
- Profile id {0} not found or is not associated with the channel.
+ Another command is currently being processed.
+ Another command '{0}' is currently running against profile '{1}'.
- Call to the server '{0}' failed.
+ The '{0}' command requires a profile id.
+ Profile '{0}' was not found or is not associated with the channel.
+ Profile '{0}' must be '{1}' to perform the command.
+ Profile '{0}' is currently being updated.
+
+ Call to server '{0}' failed.
+ A backup request for server '{0}' has been sent.
+ An update request for server '{0}' has been sent.
Count:
Map:
diff --git a/src/ARKServerManager/Lib/ServerBranchSnapshot.cs b/src/ARKServerManager/Lib/BranchSnapshot.cs
similarity index 52%
rename from src/ARKServerManager/Lib/ServerBranchSnapshot.cs
rename to src/ARKServerManager/Lib/BranchSnapshot.cs
index b9f34073..c3b0283d 100644
--- a/src/ARKServerManager/Lib/ServerBranchSnapshot.cs
+++ b/src/ARKServerManager/Lib/BranchSnapshot.cs
@@ -3,15 +3,37 @@ using System.Collections.Generic;
namespace ServerManagerTool.Lib
{
- public class ServerBranchSnapshot
+ public class BranchSnapshot
{
+ private BranchSnapshot()
+ {
+ }
+
public string BranchName = string.Empty;
public string BranchPassword = string.Empty;
+
+ public static BranchSnapshot Create(ServerProfile profile)
+ {
+ return new BranchSnapshot
+ {
+ BranchName = profile.BranchName,
+ BranchPassword = profile.BranchPassword
+ };
+ }
+
+ public static BranchSnapshot Create(ServerProfileSnapshot profile)
+ {
+ return new BranchSnapshot
+ {
+ BranchName = profile.BranchName,
+ BranchPassword = profile.BranchPassword
+ };
+ }
}
- public class ServerBranchSnapshotComparer : IEqualityComparer
+ public class BranchSnapshotComparer : IEqualityComparer
{
- public bool Equals(ServerBranchSnapshot x, ServerBranchSnapshot y)
+ public bool Equals(BranchSnapshot x, BranchSnapshot y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
@@ -24,7 +46,7 @@ namespace ServerManagerTool.Lib
return x.BranchName == y.BranchName;
}
- public int GetHashCode(ServerBranchSnapshot snapshot)
+ public int GetHashCode(BranchSnapshot snapshot)
{
//Check whether the object is null
if (snapshot is null) return 0;
diff --git a/src/ARKServerManager/Lib/Server.cs b/src/ARKServerManager/Lib/Server.cs
index bb934d88..06a7fcf9 100644
--- a/src/ARKServerManager/Lib/Server.cs
+++ b/src/ARKServerManager/Lib/Server.cs
@@ -94,7 +94,7 @@ namespace ServerManagerTool.Lib
await this.Runtime.StopAsync();
}
- public async Task UpgradeAsync(CancellationToken cancellationToken, bool updateServer, ServerBranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
+ public async Task UpgradeAsync(CancellationToken cancellationToken, bool updateServer, BranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
{
await this.Runtime.AttachToProfile(this.Profile);
var success = await this.Runtime.UpgradeAsync(cancellationToken, updateServer, branch, validate, updateMods, progressCallback);
diff --git a/src/ARKServerManager/Lib/ServerApp.cs b/src/ARKServerManager/Lib/ServerApp.cs
index 718376d3..58f637fd 100644
--- a/src/ARKServerManager/Lib/ServerApp.cs
+++ b/src/ARKServerManager/Lib/ServerApp.cs
@@ -2,6 +2,7 @@
using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
+using ServerManagerTool.Delegates;
using ServerManagerTool.Enums;
using ServerManagerTool.Plugin.Common;
using ServerManagerTool.Utils;
@@ -105,6 +106,7 @@ namespace ServerManagerTool.Lib
public int ShutdownInterval = Config.Default.ServerShutdown_GracePeriod;
public ProgressDelegate ProgressCallback = null;
public ProcessWindowStyle SteamCMDProcessWindowStyle = ProcessWindowStyle.Minimized;
+ public ServerStatusChangeDelegate ServerStatusChangeCallback = null;
public ServerApp(bool resetStartTime = false)
{
@@ -264,7 +266,15 @@ namespace ServerManagerTool.Lib
if (updateServer)
{
- UpgradeLocal(true, cancellationToken, true);
+ try
+ {
+ ServerStatusChangeCallback?.Invoke(ServerStatus.Updating);
+ UpgradeLocal(true, cancellationToken, true);
+ }
+ finally
+ {
+ ServerStatusChangeCallback?.Invoke(ServerStatus.Stopped);
+ }
}
if (ExitCode != EXITCODE_NORMALEXIT)
@@ -2869,7 +2879,7 @@ namespace ServerManagerTool.Lib
return ExitCode;
}
- public int PerformProfileUpdate(ServerBranchSnapshot branch, ServerProfileSnapshot profile)
+ public int PerformProfileUpdate(BranchSnapshot branch, ServerProfileSnapshot profile)
{
_profile = profile;
@@ -2945,7 +2955,7 @@ namespace ServerManagerTool.Lib
return ExitCode;
}
- public int PerformServerBranchUpdate(ServerBranchSnapshot branch)
+ public int PerformServerBranchUpdate(BranchSnapshot branch)
{
if (branch == null)
return EXITCODE_NORMALEXIT;
@@ -3233,8 +3243,8 @@ namespace ServerManagerTool.Lib
if (exitCode == EXITCODE_NORMALEXIT)
{
- var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => new ServerBranchSnapshot() { BranchName = p.BranchName, BranchPassword = p.BranchPassword}).Distinct(new ServerBranchSnapshotComparer()).ToArray();
- var exitCodes = new ConcurrentDictionary();
+ var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer()).ToArray();
+ var exitCodes = new ConcurrentDictionary();
// update the server cache for each branch
if (Config.Default.AutoUpdate_ParallelUpdate)
diff --git a/src/ARKServerManager/Lib/ServerProfileSnapshot.cs b/src/ARKServerManager/Lib/ServerProfileSnapshot.cs
index 940bf1e5..97367600 100644
--- a/src/ARKServerManager/Lib/ServerProfileSnapshot.cs
+++ b/src/ARKServerManager/Lib/ServerProfileSnapshot.cs
@@ -7,6 +7,10 @@ namespace ServerManagerTool.Lib
{
public class ServerProfileSnapshot
{
+ private ServerProfileSnapshot()
+ {
+ }
+
public string ProfileId;
public string ProfileName;
public string InstallDirectory;
diff --git a/src/ARKServerManager/Lib/ServerRuntime.cs b/src/ARKServerManager/Lib/ServerRuntime.cs
index b3d9f374..e69b802e 100644
--- a/src/ARKServerManager/Lib/ServerRuntime.cs
+++ b/src/ARKServerManager/Lib/ServerRuntime.cs
@@ -33,7 +33,7 @@ namespace ServerManagerTool.Lib
public event EventHandler StatusUpdate;
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
- private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
+ private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private readonly List profileNotifiers = new List();
private Process serverProcess;
private IAsyncDisposable updateRegistration;
@@ -439,7 +439,7 @@ namespace ServerManagerTool.Lib
}
CheckServerWorldFileExists();
- UpdateServerStatus(ServerStatus.Initializing, this.Availability, false);
+ UpdateServerStatus(ServerStatus.Initializing, false);
try
{
@@ -498,12 +498,12 @@ namespace ServerManagerTool.Lib
}
}
- public async Task UpgradeAsync(CancellationToken cancellationToken, bool updateServer, ServerBranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
+ public async Task UpgradeAsync(CancellationToken cancellationToken, bool updateServer, BranchSnapshot branch, bool validate, bool updateMods, ProgressDelegate progressCallback)
{
return await UpgradeAsync(cancellationToken, updateServer, branch, validate, updateMods, null, progressCallback);
}
- public async Task UpgradeAsync(CancellationToken cancellationToken, bool updateServer, ServerBranchSnapshot branch, bool validate, bool updateMods, string[] updateModIds, ProgressDelegate progressCallback)
+ public async Task UpgradeAsync(CancellationToken cancellationToken, bool updateServer, BranchSnapshot branch, bool validate, bool updateMods, string[] updateModIds, ProgressDelegate progressCallback)
{
if (updateServer && !Environment.Is64BitOperatingSystem)
{
@@ -520,7 +520,7 @@ namespace ServerManagerTool.Lib
bool isNewInstallation = this.Status == ServerStatus.Uninstalled;
- UpdateServerStatus(ServerStatus.Updating, Availability, false);
+ UpdateServerStatus(ServerStatus.Updating, false);
// Run the SteamCMD to install the server
var steamCmdFile = SteamCmdUpdater.GetSteamCmdFile(Config.Default.DataDir);
@@ -957,7 +957,7 @@ namespace ServerManagerTool.Lib
finally
{
this.lastModStatusQuery = DateTime.MinValue;
- UpdateServerStatus(ServerStatus.Stopped, Availability, false);
+ UpdateServerStatus(ServerStatus.Stopped, false);
}
}
@@ -993,6 +993,11 @@ namespace ServerManagerTool.Lib
this.lastModStatusQuery = DateTime.MinValue;
}
+ public void UpdateServerStatus(ServerStatus serverStatus, bool sendAlert)
+ {
+ UpdateServerStatus(serverStatus, Availability, sendAlert);
+ }
+
public void UpdateServerStatus(ServerStatus serverStatus, AvailabilityStatus availabilityStatus, bool sendAlert)
{
this.Status = serverStatus;
@@ -1006,32 +1011,29 @@ namespace ServerManagerTool.Lib
public void UpdateServerStatusString()
{
- switch (Status)
+ StatusString = GetServerStatusString(Status);
+ }
+
+ public static string GetServerStatusString(ServerStatus status)
+ {
+ switch (status)
{
case ServerStatus.Initializing:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
case ServerStatus.Running:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
case ServerStatus.Stopped:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
case ServerStatus.Stopping:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
case ServerStatus.Uninstalled:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
case ServerStatus.Unknown:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
case ServerStatus.Updating:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
default:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
}
}
diff --git a/src/ARKServerManager/Utils/DiscordBotHelper.cs b/src/ARKServerManager/Utils/DiscordBotHelper.cs
index 7c5b9f55..90fa05ea 100644
--- a/src/ARKServerManager/Utils/DiscordBotHelper.cs
+++ b/src/ARKServerManager/Utils/DiscordBotHelper.cs
@@ -1,11 +1,15 @@
using QueryMaster;
using ServerManagerTool.Common.Utils;
using ServerManagerTool.DiscordBot.Enums;
+using ServerManagerTool.Enums;
using ServerManagerTool.Lib;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
using WPFSharp.Globalizer;
namespace ServerManagerTool.Utils
@@ -15,6 +19,10 @@ namespace ServerManagerTool.Utils
private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private static bool _runningCommand = false;
+ private static readonly Dictionary _currentProfileCommands = new Dictionary();
+
+ public static bool HasRunningCommands => _currentProfileCommands.Count > 0;
+
public static IList HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileId)
{
// check if incoming values are valid
@@ -75,54 +83,68 @@ namespace ServerManagerTool.Utils
{
if (string.IsNullOrWhiteSpace(profileId))
{
- return new List { _globalizer.GetResourceString("DiscordBot_CommandProfileMissing") };
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Info) };
}
- var serverName = string.Empty;
- var serverIp = IPAddress.Loopback;
- var queryPort = 0;
-
- TaskUtils.RunOnUIThreadAsync(() =>
+ // check if another command is being run against the profile
+ if (_currentProfileCommands.ContainsKey(profileId))
{
- var server = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID)).FirstOrDefault();
-
- if (server is null)
- {
- throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandProfileNotFound"), profileId));
- }
-
- serverName = server.Profile.ServerName;
- if (!string.IsNullOrWhiteSpace(server.Profile.ServerIP))
- {
- IPAddress.TryParse(server.Profile.ServerIP, out serverIp);
- }
- queryPort = server.Profile.QueryPort;
- }).Wait();
-
- List response = new List();
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
+ }
+ _currentProfileCommands.Add(profileId, CommandType.Info);
try
{
- using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, new IPEndPoint(serverIp, queryPort)))
+ var serverName = string.Empty;
+ var serverIp = IPAddress.Loopback;
+ var queryPort = 0;
+
+ TaskUtils.RunOnUIThreadAsync(() =>
{
- var info = gameServer?.GetInfo();
- if (info is null)
+ var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+
+ if (server is null)
{
- response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_CommandInfoFailed"), serverName));
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
}
- else
+
+ serverName = server.Profile.ServerName;
+ if (!string.IsNullOrWhiteSpace(server.Profile.ServerIP))
{
- var mapName = _globalizer.GetResourceString($"Map_{info.Map}") ?? info.Map;
- response.Add($"```{info.Name}\n{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
+ IPAddress.TryParse(server.Profile.ServerIP, out serverIp);
+ }
+ queryPort = server.Profile.QueryPort;
+ }).Wait();
+
+ List response = new List();
+
+ try
+ {
+ using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, new IPEndPoint(serverIp, queryPort)))
+ {
+ var info = gameServer?.GetInfo();
+ if (info is null)
+ {
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
+ }
+ else
+ {
+ var mapName = _globalizer.GetResourceString($"Map_{info.Map}") ?? info.Map;
+ response.Add($"```{info.Name}\n{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
+ }
}
}
- }
- catch (Exception)
- {
- response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_CommandInfoFailed"), serverName));
- }
+ catch (Exception)
+ {
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
+ }
- return response;
+ return response;
+ }
+ finally
+ {
+ _currentProfileCommands.Remove(profileId);
+ }
}
private static IList GetServerList(string channelId)
@@ -163,7 +185,63 @@ namespace ServerManagerTool.Utils
private static IList BackupServer(string channelId, string profileId)
{
- return new List() { string.Format(_globalizer.GetResourceString("DiscordBot_CommandUnknown"), CommandType.Backup) };
+ if (string.IsNullOrWhiteSpace(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Backup) };
+ }
+
+ // check if another command is being run against the profile
+ if (_currentProfileCommands.ContainsKey(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
+ }
+ _currentProfileCommands.Add(profileId, CommandType.Backup);
+
+ ServerProfileSnapshot profile = null;
+ Task task = null;
+
+ try
+ {
+ TaskUtils.RunOnUIThreadAsync(() =>
+ {
+ var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+
+ if (server is null)
+ {
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
+ }
+
+ profile = ServerProfileSnapshot.Create(server.Profile);
+ }).Wait();
+
+ List response = new List();
+
+ var app = new ServerApp(true)
+ {
+ DeleteOldServerBackupFiles = !Config.Default.AutoBackup_EnableBackup,
+ OutputLogs = false,
+ SendAlerts = true,
+ SendEmails = false,
+ ServerProcess = ServerProcessType.Backup,
+ };
+
+ task = Task.Run(() =>
+ {
+ app.PerformProfileBackup(profile);
+ _currentProfileCommands.Remove(profileId);
+ });
+
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName));
+
+ return response;
+ }
+ finally
+ {
+ if (task is null)
+ {
+ _currentProfileCommands.Remove(profileId);
+ }
+ }
}
private static IList ShutdownServer(string channelId, string profileId)
@@ -183,7 +261,87 @@ namespace ServerManagerTool.Utils
private static IList UpdateServer(string channelId, string profileId)
{
- return new List() { string.Format(_globalizer.GetResourceString("DiscordBot_CommandUnknown"), CommandType.Update) };
+ if (string.IsNullOrWhiteSpace(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Update) };
+ }
+
+ // check if another command is being run against the profile
+ if (_currentProfileCommands.ContainsKey(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
+ }
+ _currentProfileCommands.Add(profileId, CommandType.Update);
+
+ ServerProfileSnapshot profile = null;
+ bool performRestart = false;
+ Task task = null;
+
+ try
+ {
+ TaskUtils.RunOnUIThreadAsync(() =>
+ {
+ var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+
+ if (server is null)
+ {
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
+ }
+
+ switch (server.Runtime.Status)
+ {
+ case ServerStatus.Initializing:
+ case ServerStatus.Stopping:
+ case ServerStatus.Unknown:
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, ServerRuntime.GetServerStatusString(ServerStatus.Stopped)));
+
+ case ServerStatus.Running:
+ performRestart = true;
+ break;
+
+ case ServerStatus.Updating:
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
+ }
+
+ profile = ServerProfileSnapshot.Create(server.Profile);
+ }).Wait();
+
+ List response = new List();
+
+ var app = new ServerApp(true)
+ {
+ DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+ server.Runtime.UpdateServerStatus(serverStatus, true);
+ }).Wait();
+ }
+ };
+
+ task = Task.Run(() =>
+ {
+ app.PerformProfileShutdown(profile, performRestart, true, false, CancellationToken.None);
+ _currentProfileCommands.Remove(profileId);
+ });
+
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName));
+
+ return response;
+ }
+ finally
+ {
+ if (task is null)
+ {
+ _currentProfileCommands.Remove(profileId);
+ }
+ }
}
}
}
diff --git a/src/ARKServerManager/Windows/MainWindow.xaml b/src/ARKServerManager/Windows/MainWindow.xaml
index 422c1c1c..2c7bd445 100644
--- a/src/ARKServerManager/Windows/MainWindow.xaml
+++ b/src/ARKServerManager/Windows/MainWindow.xaml
@@ -10,7 +10,7 @@
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
MinWidth="900" MinHeight="600" Width="1100" Height="900" Left="50" Top="50" WindowState="Normal"
- Loaded="Window_Loaded" SizeChanged="Window_SizeChanged" StateChanged="Window_StateChanged" LocationChanged="Window_LocationChanged"
+ Loaded="MainWindow_Loaded" SizeChanged="MainWindow_SizeChanged" StateChanged="MainWindow_StateChanged" LocationChanged="MainWindow_LocationChanged"
Name="Main" Icon="../Art/favicon.ico" Title="{DynamicResource MainWindow_Title}">
diff --git a/src/ARKServerManager/Windows/MainWindow.xaml.cs b/src/ARKServerManager/Windows/MainWindow.xaml.cs
index d4ea4f77..352049ae 100644
--- a/src/ARKServerManager/Windows/MainWindow.xaml.cs
+++ b/src/ARKServerManager/Windows/MainWindow.xaml.cs
@@ -6,6 +6,7 @@ using ServerManagerTool.Common.Utils;
using ServerManagerTool.Enums;
using ServerManagerTool.Lib;
using ServerManagerTool.Plugin.Common;
+using ServerManagerTool.Utils;
using ServerManagerTool.Windows;
using System;
using System.Diagnostics;
@@ -169,7 +170,7 @@ namespace ServerManagerTool
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
}
- private void Window_Loaded(object sender, RoutedEventArgs e)
+ private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
//
// Kick off the initialization.
@@ -199,15 +200,7 @@ namespace ServerManagerTool
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
}
- private void Window_Closed(object sender, EventArgs e)
- {
- if (sender is Window window)
- window.Closed -= Window_Closed;
-
- this.Activate();
- }
-
- private void Window_LocationChanged(object sender, EventArgs e)
+ private void MainWindow_LocationChanged(object sender, EventArgs e)
{
if (this.WindowState == WindowState.Normal)
{
@@ -216,7 +209,7 @@ namespace ServerManagerTool
}
}
- private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
+ private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (this.WindowState == WindowState.Normal)
{
@@ -225,7 +218,7 @@ namespace ServerManagerTool
}
}
- private void Window_StateChanged(object sender, EventArgs e)
+ private void MainWindow_StateChanged(object sender, EventArgs e)
{
if (Config.Default.MainWindow_MinimizeToTray && this.WindowState == WindowState.Minimized)
{
@@ -233,8 +226,26 @@ namespace ServerManagerTool
}
}
+ private void Window_Closed(object sender, EventArgs e)
+ {
+ if (sender is Window window)
+ window.Closed -= Window_Closed;
+
+ this.Activate();
+ }
+
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
+ if (DiscordBotHelper.HasRunningCommands)
+ {
+ var result = MessageBox.Show(_globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsLabel"), _globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question);
+ if (result == MessageBoxResult.No)
+ {
+ e.Cancel = true;
+ return;
+ }
+ }
+
base.OnClosing(e);
RCONWindow.CloseAllWindows();
PlayerListWindow.CloseAllWindows();
diff --git a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs
index 6e141131..35f78c99 100644
--- a/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs
+++ b/src/ARKServerManager/Windows/ServerMonitorWindow.xaml.cs
@@ -623,7 +623,7 @@ namespace ServerManagerTool.Windows
await Task.Delay(1000);
- var branch = new ServerBranchSnapshot() { BranchName = serverProfile.BranchName, BranchPassword = serverProfile.BranchPassword };
+ var branch = BranchSnapshot.Create(serverProfile);
return await server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
}
else
diff --git a/src/ARKServerManager/Windows/ServerSettingsControl.xaml.cs b/src/ARKServerManager/Windows/ServerSettingsControl.xaml.cs
index 9b53372e..f78a1888 100644
--- a/src/ARKServerManager/Windows/ServerSettingsControl.xaml.cs
+++ b/src/ARKServerManager/Windows/ServerSettingsControl.xaml.cs
@@ -4266,7 +4266,7 @@ namespace ServerManagerTool
await Task.Delay(1000);
- var branch = new ServerBranchSnapshot() { BranchName = this.Server.Profile.BranchName, BranchPassword = this.Server.Profile.BranchPassword };
+ var branch = BranchSnapshot.Create(this.Server.Profile);
return await this.Server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
}
else
diff --git a/src/ConanServerManager/ConanServerManager.csproj b/src/ConanServerManager/ConanServerManager.csproj
index 463cdd2a..313ddc73 100644
--- a/src/ConanServerManager/ConanServerManager.csproj
+++ b/src/ConanServerManager/ConanServerManager.csproj
@@ -160,6 +160,7 @@
MSBuild:Compile
Designer
+
diff --git a/src/ConanServerManager/Delegates/ServerStatusChangeDelegate.cs b/src/ConanServerManager/Delegates/ServerStatusChangeDelegate.cs
new file mode 100644
index 00000000..c7ab834a
--- /dev/null
+++ b/src/ConanServerManager/Delegates/ServerStatusChangeDelegate.cs
@@ -0,0 +1,6 @@
+using ServerManagerTool.Enums;
+
+namespace ServerManagerTool.Delegates
+{
+ public delegate void ServerStatusChangeDelegate(ServerStatus serverStatus);
+}
diff --git a/src/ConanServerManager/Enums/ServerProcessType.cs b/src/ConanServerManager/Enums/ServerProcessType.cs
index 861e2081..7298dfd9 100644
--- a/src/ConanServerManager/Enums/ServerProcessType.cs
+++ b/src/ConanServerManager/Enums/ServerProcessType.cs
@@ -10,5 +10,6 @@
Backup,
Shutdown,
Restart,
+ Update,
}
}
diff --git a/src/ConanServerManager/Globalization/en-US/en-US.xaml b/src/ConanServerManager/Globalization/en-US/en-US.xaml
index c56e4c92..831ab091 100644
--- a/src/ConanServerManager/Globalization/en-US/en-US.xaml
+++ b/src/ConanServerManager/Globalization/en-US/en-US.xaml
@@ -628,6 +628,9 @@
Reinstall SteamCMD Error
An error occured while trying to reinstall SteamCMD. This has left SteamCmd in an unstable state, try reinstalling again or please report this.\r\nException: {0}
+ Discord Bot Running Commands
+ The discord bot has one or more running commands, do you want to continue shutting down the server manager?
+
Start Server Confirmation
You are about to start the server, do you want to continue?
Shutdown Server Confirmation
@@ -1217,12 +1220,17 @@
Command '{0}' has not been implemented.
Unknown command '{0}'.
- Another command is currently running.
+ Another command is currently being processed.
+ Another command '{0}' is currently running against profile '{1}'.
- The command requires a profile id.
- Profile id {0} not found or is not associated with the channel.
+ The '{0}' command requires a profile id.
+ Profile '{0}' was not found or is not associated with the channel.
+ Profile '{0}' must be '{1}' to perform the command.
+ Profile '{0}' is currently being updated.
- Call to the server '{0}' failed.
+ Call to server '{0}' failed.
+ A backup request for server '{0}' has been sent.
+ An update request for server '{0}' has been sent.
Count:
Map:
diff --git a/src/ConanServerManager/Lib/BranchSnapshot.cs b/src/ConanServerManager/Lib/BranchSnapshot.cs
index 2b81437d..c3b0283d 100644
--- a/src/ConanServerManager/Lib/BranchSnapshot.cs
+++ b/src/ConanServerManager/Lib/BranchSnapshot.cs
@@ -5,8 +5,30 @@ namespace ServerManagerTool.Lib
{
public class BranchSnapshot
{
+ private BranchSnapshot()
+ {
+ }
+
public string BranchName = string.Empty;
public string BranchPassword = string.Empty;
+
+ public static BranchSnapshot Create(ServerProfile profile)
+ {
+ return new BranchSnapshot
+ {
+ BranchName = profile.BranchName,
+ BranchPassword = profile.BranchPassword
+ };
+ }
+
+ public static BranchSnapshot Create(ServerProfileSnapshot profile)
+ {
+ return new BranchSnapshot
+ {
+ BranchName = profile.BranchName,
+ BranchPassword = profile.BranchPassword
+ };
+ }
}
public class BranchSnapshotComparer : IEqualityComparer
diff --git a/src/ConanServerManager/Lib/ServerApp.cs b/src/ConanServerManager/Lib/ServerApp.cs
index 7d745a88..cc50048a 100644
--- a/src/ConanServerManager/Lib/ServerApp.cs
+++ b/src/ConanServerManager/Lib/ServerApp.cs
@@ -3,6 +3,7 @@ using ServerManagerTool.Common;
using ServerManagerTool.Common.Lib;
using ServerManagerTool.Common.Model;
using ServerManagerTool.Common.Utils;
+using ServerManagerTool.Delegates;
using ServerManagerTool.Enums;
using ServerManagerTool.Plugin.Common;
using ServerManagerTool.Utils;
@@ -108,6 +109,7 @@ namespace ServerManagerTool.Lib
public int ShutdownInterval = Config.Default.ServerShutdown_GracePeriod;
public ProgressDelegate ProgressCallback = null;
public ProcessWindowStyle SteamCMDProcessWindowStyle = ProcessWindowStyle.Minimized;
+ public ServerStatusChangeDelegate ServerStatusChangeCallback = null;
public ServerApp(bool resetStartTime = false)
{
@@ -261,7 +263,15 @@ namespace ServerManagerTool.Lib
if (updateServer)
{
- UpgradeLocal(true, steamCmdRemoveQuit, cancellationToken, true);
+ try
+ {
+ ServerStatusChangeCallback?.Invoke(ServerStatus.Updating);
+ UpgradeLocal(true, steamCmdRemoveQuit, cancellationToken, true);
+ }
+ finally
+ {
+ ServerStatusChangeCallback?.Invoke(ServerStatus.Stopped);
+ }
}
if (ExitCode != EXITCODE_NORMALEXIT)
@@ -3060,7 +3070,7 @@ namespace ServerManagerTool.Lib
if (exitCode == EXITCODE_NORMALEXIT)
{
- var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => new BranchSnapshot() { BranchName = p.BranchName, BranchPassword = p.BranchPassword }).Distinct(new BranchSnapshotComparer()).ToArray();
+ var branches = _profiles.Keys.Where(p => p.EnableAutoUpdate).Select(p => BranchSnapshot.Create(p)).Distinct(new BranchSnapshotComparer()).ToArray();
var exitCodes = new ConcurrentDictionary();
// update the server cache for each branch
diff --git a/src/ConanServerManager/Lib/ServerProfileSnapshot.cs b/src/ConanServerManager/Lib/ServerProfileSnapshot.cs
index 543aa4c2..cd341e57 100644
--- a/src/ConanServerManager/Lib/ServerProfileSnapshot.cs
+++ b/src/ConanServerManager/Lib/ServerProfileSnapshot.cs
@@ -7,6 +7,10 @@ namespace ServerManagerTool.Lib
{
public class ServerProfileSnapshot
{
+ private ServerProfileSnapshot()
+ {
+ }
+
public string ProfileId;
public string ProfileName;
public string ServerName;
diff --git a/src/ConanServerManager/Lib/ServerRuntime.cs b/src/ConanServerManager/Lib/ServerRuntime.cs
index 479e14e5..0d9e20da 100644
--- a/src/ConanServerManager/Lib/ServerRuntime.cs
+++ b/src/ConanServerManager/Lib/ServerRuntime.cs
@@ -32,7 +32,7 @@ namespace ServerManagerTool.Lib
public event EventHandler StatusUpdate;
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
- private readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
+ private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private readonly List profileNotifiers = new List();
private Process serverProcess;
private IAsyncDisposable updateRegistration;
@@ -442,7 +442,7 @@ namespace ServerManagerTool.Lib
}
}
- UpdateServerStatus(ServerStatus.Initializing, this.Availability, false);
+ UpdateServerStatus(ServerStatus.Initializing, false);
try
{
@@ -516,7 +516,7 @@ namespace ServerManagerTool.Lib
bool isNewInstallation = this.Status == ServerStatus.Uninstalled;
- UpdateServerStatus(ServerStatus.Updating, Availability, false);
+ UpdateServerStatus(ServerStatus.Updating, false);
// Run the SteamCMD to install the server
var steamCmdFile = SteamCmdUpdater.GetSteamCmdFile(Config.Default.DataPath);
@@ -938,7 +938,7 @@ namespace ServerManagerTool.Lib
finally
{
this.lastModStatusQuery = DateTime.MinValue;
- UpdateServerStatus(ServerStatus.Stopped, Availability, false);
+ UpdateServerStatus(ServerStatus.Stopped, false);
}
}
@@ -961,6 +961,11 @@ namespace ServerManagerTool.Lib
this.lastModStatusQuery = DateTime.MinValue;
}
+ public void UpdateServerStatus(ServerStatus serverStatus, bool sendAlert)
+ {
+ UpdateServerStatus(serverStatus, Availability, sendAlert);
+ }
+
public void UpdateServerStatus(ServerStatus serverStatus, AvailabilityStatus availabilityStatus, bool sendAlert)
{
this.Status = serverStatus;
@@ -974,32 +979,29 @@ namespace ServerManagerTool.Lib
public void UpdateServerStatusString()
{
- switch (Status)
+ StatusString = GetServerStatusString(Status);
+ }
+
+ public static string GetServerStatusString(ServerStatus status)
+ {
+ switch (status)
{
case ServerStatus.Initializing:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusInitializingLabel");
case ServerStatus.Running:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusRunningLabel");
case ServerStatus.Stopped:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppedLabel");
case ServerStatus.Stopping:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusStoppingLabel");
case ServerStatus.Uninstalled:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUninstalledLabel");
case ServerStatus.Unknown:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
case ServerStatus.Updating:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUpdatingLabel");
default:
- StatusString = _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
- break;
+ return _globalizer.GetResourceString("ServerSettings_RuntimeStatusUnknownLabel");
}
}
diff --git a/src/ConanServerManager/Utils/DiscordBotHelper.cs b/src/ConanServerManager/Utils/DiscordBotHelper.cs
index fc793e95..b1f16177 100644
--- a/src/ConanServerManager/Utils/DiscordBotHelper.cs
+++ b/src/ConanServerManager/Utils/DiscordBotHelper.cs
@@ -1,11 +1,15 @@
using QueryMaster;
using ServerManagerTool.Common.Utils;
using ServerManagerTool.DiscordBot.Enums;
+using ServerManagerTool.Enums;
using ServerManagerTool.Lib;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
using WPFSharp.Globalizer;
namespace ServerManagerTool.Utils
@@ -15,6 +19,10 @@ namespace ServerManagerTool.Utils
private static readonly GlobalizedApplication _globalizer = GlobalizedApplication.Instance;
private static bool _runningCommand = false;
+ private static readonly Dictionary _currentProfileCommands = new Dictionary();
+
+ public static bool HasRunningCommands => _currentProfileCommands.Count > 0;
+
public static IList HandleDiscordCommand(CommandType commandType, string serverId, string channelId, string profileId)
{
// check if incoming values are valid
@@ -57,7 +65,8 @@ namespace ServerManagerTool.Utils
}
catch (Exception ex)
{
- return new string[] { ex.Message };
+ var message = ex.InnerException is null ? ex.Message : ex.InnerException.Message;
+ return new string[] { message };
}
finally
{
@@ -74,54 +83,68 @@ namespace ServerManagerTool.Utils
{
if (string.IsNullOrWhiteSpace(profileId))
{
- return new List { _globalizer.GetResourceString("DiscordBot_CommandProfileMissing") };
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Info) };
}
- var serverName = string.Empty;
- var serverIp = IPAddress.Loopback;
- var queryPort = 0;
-
- TaskUtils.RunOnUIThreadAsync(() =>
+ // check if another command is being run against the profile
+ if (_currentProfileCommands.ContainsKey(profileId))
{
- var server = ServerManager.Instance.Servers.Where(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID)).FirstOrDefault();
-
- if (server is null)
- {
- throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_CommandProfileNotFound"), profileId));
- }
-
- serverName = server.Profile.ServerName;
- if (!string.IsNullOrWhiteSpace(server.Profile.ServerIP))
- {
- IPAddress.TryParse(server.Profile.ServerIP, out serverIp);
- }
- queryPort = server.Profile.QueryPort;
- }).Wait();
-
- List response = new List();
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
+ }
+ _currentProfileCommands.Add(profileId, CommandType.Info);
try
{
- using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, new IPEndPoint(serverIp, queryPort)))
+ var serverName = string.Empty;
+ var serverIp = IPAddress.Loopback;
+ var queryPort = 0;
+
+ TaskUtils.RunOnUIThreadAsync(() =>
{
- var info = gameServer?.GetInfo();
- if (info is null)
+ var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+
+ if (server is null)
{
- response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_CommandInfoFailed"), serverName));
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
}
- else
+
+ serverName = server.Profile.ServerName;
+ if (!string.IsNullOrWhiteSpace(server.Profile.ServerIP))
{
- var mapName = _globalizer.GetResourceString($"Map_{info.Map}") ?? info.Map;
- response.Add($"```{info.Name}\n{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
+ IPAddress.TryParse(server.Profile.ServerIP, out serverIp);
+ }
+ queryPort = server.Profile.QueryPort;
+ }).Wait();
+
+ List response = new List();
+
+ try
+ {
+ using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, new IPEndPoint(serverIp, queryPort)))
+ {
+ var info = gameServer?.GetInfo();
+ if (info is null)
+ {
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
+ }
+ else
+ {
+ var mapName = _globalizer.GetResourceString($"Map_{info.Map}") ?? info.Map;
+ response.Add($"```{info.Name}\n{_globalizer.GetResourceString("DiscordBot_MapLabel")} {mapName}\n{_globalizer.GetResourceString("ServerSettings_PlayersLabel")} {info.Players} / {info.MaxPlayers}```");
+ }
}
}
- }
- catch (Exception)
- {
- response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_CommandInfoFailed"), serverName));
- }
+ catch (Exception)
+ {
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_InfoFailed"), serverName));
+ }
- return response;
+ return response;
+ }
+ finally
+ {
+ _currentProfileCommands.Remove(profileId);
+ }
}
private static IList GetServerList(string channelId)
@@ -162,7 +185,63 @@ namespace ServerManagerTool.Utils
private static IList BackupServer(string channelId, string profileId)
{
- return new List() { string.Format(_globalizer.GetResourceString("DiscordBot_CommandUnknown"), CommandType.Backup) };
+ if (string.IsNullOrWhiteSpace(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Backup) };
+ }
+
+ // check if another command is being run against the profile
+ if (_currentProfileCommands.ContainsKey(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
+ }
+ _currentProfileCommands.Add(profileId, CommandType.Backup);
+
+ ServerProfileSnapshot profile = null;
+ Task task = null;
+
+ try
+ {
+ TaskUtils.RunOnUIThreadAsync(() =>
+ {
+ var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+
+ if (server is null)
+ {
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
+ }
+
+ profile = ServerProfileSnapshot.Create(server.Profile);
+ }).Wait();
+
+ List response = new List();
+
+ var app = new ServerApp(true)
+ {
+ DeleteOldServerBackupFiles = !Config.Default.AutoBackup_EnableBackup,
+ OutputLogs = false,
+ SendAlerts = true,
+ SendEmails = false,
+ ServerProcess = ServerProcessType.Backup,
+ };
+
+ task = Task.Run(() =>
+ {
+ app.PerformProfileBackup(profile);
+ _currentProfileCommands.Remove(profileId);
+ });
+
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_BackupRequested"), profile.ServerName));
+
+ return response;
+ }
+ finally
+ {
+ if (task is null)
+ {
+ _currentProfileCommands.Remove(profileId);
+ }
+ }
}
private static IList ShutdownServer(string channelId, string profileId)
@@ -182,7 +261,87 @@ namespace ServerManagerTool.Utils
private static IList UpdateServer(string channelId, string profileId)
{
- return new List() { string.Format(_globalizer.GetResourceString("DiscordBot_CommandUnknown"), CommandType.Update) };
+ if (string.IsNullOrWhiteSpace(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_ProfileMissing"), CommandType.Update) };
+ }
+
+ // check if another command is being run against the profile
+ if (_currentProfileCommands.ContainsKey(profileId))
+ {
+ return new List { string.Format(_globalizer.GetResourceString("DiscordBot_CommandRunningProfile"), _currentProfileCommands[profileId], profileId) };
+ }
+ _currentProfileCommands.Add(profileId, CommandType.Update);
+
+ ServerProfileSnapshot profile = null;
+ bool performRestart = false;
+ Task task = null;
+
+ try
+ {
+ TaskUtils.RunOnUIThreadAsync(() =>
+ {
+ var server = ServerManager.Instance.Servers.FirstOrDefault(s => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+
+ if (server is null)
+ {
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileNotFound"), profileId));
+ }
+
+ switch (server.Runtime.Status)
+ {
+ case ServerStatus.Initializing:
+ case ServerStatus.Stopping:
+ case ServerStatus.Unknown:
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileBadStatus"), profileId, ServerRuntime.GetServerStatusString(ServerStatus.Stopped)));
+
+ case ServerStatus.Running:
+ performRestart = true;
+ break;
+
+ case ServerStatus.Updating:
+ throw new Exception(string.Format(_globalizer.GetResourceString("DiscordBot_ProfileUpdating"), profileId));
+ }
+
+ profile = ServerProfileSnapshot.Create(server.Profile);
+ }).Wait();
+
+ List response = new List();
+
+ var app = new ServerApp(true)
+ {
+ DeleteOldServerBackupFiles = !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 => Equals(channelId, s.Profile.DiscordChannelId) && Equals(profileId, s.Profile.ProfileID));
+ server.Runtime.UpdateServerStatus(serverStatus, true);
+ }).Wait();
+ }
+ };
+
+ task = Task.Run(() =>
+ {
+ app.PerformProfileShutdown(profile, performRestart, true, false, false, CancellationToken.None);
+ _currentProfileCommands.Remove(profileId);
+ });
+
+ response.Add(string.Format(_globalizer.GetResourceString("DiscordBot_UpdateRequested"), profile.ServerName));
+
+ return response;
+ }
+ finally
+ {
+ if (task is null)
+ {
+ _currentProfileCommands.Remove(profileId);
+ }
+ }
}
}
}
diff --git a/src/ConanServerManager/Windows/MainWindow.xaml b/src/ConanServerManager/Windows/MainWindow.xaml
index e83bab9b..8a4cd1d7 100644
--- a/src/ConanServerManager/Windows/MainWindow.xaml
+++ b/src/ConanServerManager/Windows/MainWindow.xaml
@@ -10,7 +10,7 @@
xmlns:com="clr-namespace:ServerManagerTool.Common;assembly=ServerManager.Common"
xmlns:enum="clr-namespace:ServerManagerTool.Enums"
MinWidth="900" MinHeight="600" Width="1100" Height="900" Left="50" Top="50" WindowState="Normal"
- Loaded="Window_Loaded" SizeChanged="Window_SizeChanged" StateChanged="Window_StateChanged" LocationChanged="Window_LocationChanged"
+ Loaded="MainWindow_Loaded" SizeChanged="MainWindow_SizeChanged" StateChanged="MainWindow_StateChanged" LocationChanged="MainWindow_LocationChanged"
Name="Main" Icon="../Art/favicon.ico" Title="{DynamicResource MainWindow_Title}">
diff --git a/src/ConanServerManager/Windows/MainWindow.xaml.cs b/src/ConanServerManager/Windows/MainWindow.xaml.cs
index be46d9b5..cbd30acb 100644
--- a/src/ConanServerManager/Windows/MainWindow.xaml.cs
+++ b/src/ConanServerManager/Windows/MainWindow.xaml.cs
@@ -6,6 +6,7 @@ using ServerManagerTool.Common.Utils;
using ServerManagerTool.Enums;
using ServerManagerTool.Lib;
using ServerManagerTool.Plugin.Common;
+using ServerManagerTool.Utils;
using ServerManagerTool.Windows;
using System;
using System.Diagnostics;
@@ -162,7 +163,7 @@ namespace ServerManagerTool
GlobalizedApplication.Instance.GlobalizationManager.ResourceDictionaryChangedEvent += ResourceDictionaryChangedEvent;
}
- private void Window_Loaded(object sender, RoutedEventArgs e)
+ private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
//
// Kick off the initialization.
@@ -192,15 +193,7 @@ namespace ServerManagerTool
this.scheduledTaskChecker.PostAction(CheckForScheduledTasks).DoNotWait();
}
- private void Window_Closed(object sender, EventArgs e)
- {
- if (sender is Window window)
- window.Closed -= Window_Closed;
-
- this.Activate();
- }
-
- private void Window_LocationChanged(object sender, EventArgs e)
+ private void MainWindow_LocationChanged(object sender, EventArgs e)
{
if (this.WindowState == WindowState.Normal)
{
@@ -209,7 +202,7 @@ namespace ServerManagerTool
}
}
- private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
+ private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (this.WindowState == WindowState.Normal)
{
@@ -218,7 +211,7 @@ namespace ServerManagerTool
}
}
- private void Window_StateChanged(object sender, EventArgs e)
+ private void MainWindow_StateChanged(object sender, EventArgs e)
{
if (Config.Default.MainWindow_MinimizeToTray && this.WindowState == WindowState.Minimized)
{
@@ -226,8 +219,26 @@ namespace ServerManagerTool
}
}
+ private void Window_Closed(object sender, EventArgs e)
+ {
+ if (sender is Window window)
+ window.Closed -= Window_Closed;
+
+ this.Activate();
+ }
+
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
+ if (DiscordBotHelper.HasRunningCommands)
+ {
+ var result = MessageBox.Show(_globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsLabel"), _globalizer.GetResourceString("MainWindow_DiscordBot_RunningCommandsTitle"), MessageBoxButton.YesNo, MessageBoxImage.Question);
+ if (result == MessageBoxResult.No)
+ {
+ e.Cancel = true;
+ return;
+ }
+ }
+
base.OnClosing(e);
RconWindow.CloseAllWindows();
PlayerListWindow.CloseAllWindows();
diff --git a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs b/src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs
index 7b7990c4..62f3b844 100644
--- a/src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs
+++ b/src/ConanServerManager/Windows/ServerMonitorWindow.xaml.cs
@@ -620,7 +620,7 @@ namespace ServerManagerTool.Windows
await Task.Delay(1000);
- var branch = new BranchSnapshot() { BranchName = serverProfile.BranchName, BranchPassword = serverProfile.BranchPassword };
+ var branch = BranchSnapshot.Create(serverProfile);
return await server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
}
else
diff --git a/src/ConanServerManager/Windows/ServerSettingsControl.xaml.cs b/src/ConanServerManager/Windows/ServerSettingsControl.xaml.cs
index 24825056..55975a98 100644
--- a/src/ConanServerManager/Windows/ServerSettingsControl.xaml.cs
+++ b/src/ConanServerManager/Windows/ServerSettingsControl.xaml.cs
@@ -1449,7 +1449,7 @@ namespace ServerManagerTool
await Task.Delay(1000);
- var branch = new BranchSnapshot() { BranchName = this.Server.Profile.BranchName, BranchPassword = this.Server.Profile.BranchPassword };
+ var branch = BranchSnapshot.Create(this.Server.Profile);
return await this.Server.UpgradeAsync(_upgradeCancellationSource.Token, updateServer, branch, true, updateMods, (p, m, n) => { TaskUtils.RunOnUIThreadAsync(() => { window?.AddMessage(m, n); }).DoNotWait(); });
}
else
diff --git a/src/ServerManager.Discord/Modules/ServerCommandModule.cs b/src/ServerManager.Discord/Modules/ServerCommandModule.cs
index 6948f4bc..57b772b2 100644
--- a/src/ServerManager.Discord/Modules/ServerCommandModule.cs
+++ b/src/ServerManager.Discord/Modules/ServerCommandModule.cs
@@ -23,15 +23,6 @@ namespace ServerManagerTool.DiscordBot.Modules
_config = config;
}
- [Command("backup", RunMode = RunMode.Async)]
- [Summary("Perform a backup of the server")]
- [Remarks("backup")]
- [RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
- public async Task BackupServerAsync()
- {
- await BackupServerAsync(null);
- }
-
[Command("backup", RunMode = RunMode.Async)]
[Summary("Perform a backup of the server")]
[Remarks("backup profileId")]
@@ -63,15 +54,6 @@ namespace ServerManagerTool.DiscordBot.Modules
}
}
- [Command("shutdown", RunMode = RunMode.Async)]
- [Summary("Shuts down the server properly")]
- [Remarks("shutdown")]
- [RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
- public async Task ShutdownServerAsync()
- {
- await ShutdownServerAsync(null);
- }
-
[Command("shutdown", RunMode = RunMode.Async)]
[Summary("Shuts down the server properly")]
[Remarks("shutdown profileId")]
@@ -103,15 +85,6 @@ namespace ServerManagerTool.DiscordBot.Modules
}
}
- [Command("start", RunMode = RunMode.Async)]
- [Summary("Starts the server")]
- [Remarks("start")]
- [RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
- public async Task StartServerAsync()
- {
- await StartServerAsync(null);
- }
-
[Command("start", RunMode = RunMode.Async)]
[Summary("Starts the server")]
[Remarks("start profileId")]
@@ -143,15 +116,6 @@ namespace ServerManagerTool.DiscordBot.Modules
}
}
- [Command("stop", RunMode = RunMode.Async)]
- [Summary("Forcibly stops the server")]
- [Remarks("stop")]
- [RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
- public async Task StopServerAsync()
- {
- await StopServerAsync(null);
- }
-
[Command("stop", RunMode = RunMode.Async)]
[Summary("Forcibly stops the server")]
[Remarks("stop profileId")]
@@ -183,15 +147,6 @@ namespace ServerManagerTool.DiscordBot.Modules
}
}
- [Command("update", RunMode = RunMode.Async)]
- [Summary("Updates the server")]
- [Remarks("update")]
- [RequireBotPermission(ChannelPermission.ViewChannel | ChannelPermission.SendMessages)]
- public async Task UpdateServerAsync()
- {
- await UpdateServerAsync(null);
- }
-
[Command("update", RunMode = RunMode.Async)]
[Summary("Updates the server")]
[Remarks("update profileId")]