mirror of
https://github.com/tribufu/ServerManagers
synced 2026-05-06 15:17:34 +00:00
Availability Changes
- changed Waiting for Publication to more specific Statuses.
This commit is contained in:
parent
a14f91c412
commit
09659d9ae2
20 changed files with 600 additions and 410 deletions
|
|
@ -683,12 +683,12 @@ namespace ServerManagerTool
|
|||
if (Config.Default.LoggingEnabled)
|
||||
{
|
||||
while (!LogManager.IsLoggingEnabled())
|
||||
LogManager.EnableLogging();
|
||||
LogManager.ResumeLogging();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (LogManager.IsLoggingEnabled())
|
||||
LogManager.DisableLogging();
|
||||
LogManager.SuspendLogging();
|
||||
}
|
||||
|
||||
Debug.WriteLine($"Logging Enabled: {LogManager.IsLoggingEnabled()}");
|
||||
|
|
|
|||
|
|
@ -968,14 +968,19 @@
|
|||
<sys:String x:Key="ServerSettings_LastStartedLabel">Last Start Time:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AvailabilityLabel">Availability:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AvailabilityTooltip">The status of the server on Steam.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Unknown">Unknown</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_SetPublicIP">Set Public IP</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Unavailable">Unavailable</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Waiting">Waiting for publication</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Available">Available</sys:String>
|
||||
<sys:String x:Key="ServerSettings_PlayersLabel">Players:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_PlayersTooltip">The current number of players connected to the server.</sys:String>
|
||||
|
||||
<sys:String x:Key="ServerSettings_Availability_Unknown">Unknown</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Unavailable">Unavailable</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_UnavailableTootip">Server in not accessible</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_LocalOnly">LAN Only</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_LocalOnlyTootip">Server accessible via Local IP only. Port Forwarding, Firewall or CGNAT etc are preventing public access.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_PublicOnly">Available - No Loopback</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_PublicOnlyTootip">Server accessible via Local IP and Public IP, loopback not available. Server is public but Public IP not accessible via LAN.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Available">Available</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_AvailableTootip">Server accessible via Local IP and Public IP</sys:String>
|
||||
|
||||
<sys:String x:Key="ServerSettings_RuntimeStatusInitializingLabel">Initializing</sys:String>
|
||||
<sys:String x:Key="ServerSettings_RuntimeStatusRunningLabel">Running</sys:String>
|
||||
<sys:String x:Key="ServerSettings_RuntimeStatusStoppedLabel">Stopped</sys:String>
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ namespace ServerManagerTool.Lib
|
|||
new[] {
|
||||
ServerProfile.ProfileNameProperty,
|
||||
ServerProfile.InstallDirectoryProperty,
|
||||
ServerProfile.QueryPortProperty,
|
||||
ServerProfile.ServerPortProperty,
|
||||
ServerProfile.QueryPortProperty,
|
||||
ServerProfile.ServerIPProperty,
|
||||
ServerProfile.MaxPlayersProperty,
|
||||
|
||||
|
|
@ -196,7 +196,7 @@ namespace ServerManagerTool.Lib
|
|||
//
|
||||
if (!ushort.TryParse(this.ProfileSnapshot.QueryPort.ToString(), out _))
|
||||
{
|
||||
Debug.WriteLine($"Port is out of range ({this.ProfileSnapshot.QueryPort})");
|
||||
_logger.Error($"Port is out of range ({this.ProfileSnapshot.QueryPort})");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ namespace ServerManagerTool.Lib
|
|||
// Get the public endpoint for querying Steam
|
||||
//
|
||||
steamServerQueryEndPoint = null;
|
||||
if (!String.IsNullOrWhiteSpace(Config.Default.MachinePublicIP))
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.MachinePublicIP))
|
||||
{
|
||||
if (IPAddress.TryParse(Config.Default.MachinePublicIP, out IPAddress steamServerIpAddress))
|
||||
{
|
||||
|
|
@ -226,7 +226,7 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Failed to resolve DNS address {0}: {1}\r\n{2}", Config.Default.MachinePublicIP, ex.Message, ex.StackTrace);
|
||||
_logger.Error($"{nameof(GetServerEndpoints)} - Failed to resolve DNS address {Config.Default.MachinePublicIP}. {ex.Message}\r\n{ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
private void ProcessStatusUpdate(IAsyncDisposable registration, ServerStatusUpdate update)
|
||||
{
|
||||
if(!Object.ReferenceEquals(registration, this.updateRegistration))
|
||||
if (!ReferenceEquals(registration, this.updateRegistration))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -246,64 +246,90 @@ namespace ServerManagerTool.Lib
|
|||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var oldStatus = this.Status;
|
||||
var oldAvailability = this.Availability;
|
||||
|
||||
switch (update.Status)
|
||||
{
|
||||
case WatcherServerStatus.Unknown:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Unknown, AvailabilityStatus.Unknown, false);
|
||||
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.NotInstalled:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Uninstalled, AvailabilityStatus.Unavailable, false);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Initializing:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Initializing, AvailabilityStatus.Unavailable, oldStatus != ServerStatus.Initializing && oldStatus != ServerStatus.Unknown);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Stopped:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Stopped, AvailabilityStatus.Unavailable, oldStatus == ServerStatus.Initializing || oldStatus == ServerStatus.Running || oldStatus == ServerStatus.Stopping);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Unknown:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Unknown, AvailabilityStatus.Unknown, false);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
case WatcherServerStatus.Initializing:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Initializing, AvailabilityStatus.Unavailable, oldStatus != ServerStatus.Initializing && oldStatus != ServerStatus.Unknown);
|
||||
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.RunningLocalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
{
|
||||
UpdateServerStatus(ServerStatus.Running, this.Availability != AvailabilityStatus.Available ? AvailabilityStatus.Waiting : this.Availability, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
UpdateServerStatus(ServerStatus.Running, oldAvailability != AvailabilityStatus.Available ? AvailabilityStatus.LocalOnly : AvailabilityStatus.Available, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Start();
|
||||
}
|
||||
else
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
{
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.RunningExternalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
{
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.Waiting, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.PublicOnly, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Start();
|
||||
}
|
||||
else
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
{
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Published:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
{
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.Available, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Start();
|
||||
}
|
||||
else
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
{
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +342,7 @@ namespace ServerManagerTool.Lib
|
|||
if (match.Success && match.Groups.Count >= 2)
|
||||
{
|
||||
var serverVersion = match.Groups[1].Value;
|
||||
if (!String.IsNullOrWhiteSpace(serverVersion) && Version.TryParse(serverVersion, out Version temp))
|
||||
if (!string.IsNullOrWhiteSpace(serverVersion) && Version.TryParse(serverVersion, out Version temp))
|
||||
{
|
||||
this.Version = temp;
|
||||
}
|
||||
|
|
@ -512,7 +538,7 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
if (updateServer && !Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
var result = MessageBox.Show("The ARK server requires a 64-bit operating system to run. Your operating system is 32-bit and therefore the Ark Server Manager will be unable to start the server, but you may still install it or load and save profiles and settings files for use on other machines.\r\n\r\nDo you wish to continue?", "64-bit OS Required", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
var result = MessageBox.Show("The server requires a 64-bit operating system to run. Your operating system is 32-bit and therefore the Ark Server Manager will be unable to start the server, but you may still install it or load and save profiles and settings files for use on other machines.\r\n\r\nDo you wish to continue?", "64-bit OS Required", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (result == MessageBoxResult.No)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -583,10 +609,10 @@ namespace ServerManagerTool.Lib
|
|||
int count = 0;
|
||||
await Task.Run(() =>
|
||||
ServerApp.DirectoryCopy(cacheFolder, installationFolder, true, Config.Default.AutoUpdate_UseSmartCopy, (p, m, n) =>
|
||||
{
|
||||
count++;
|
||||
progressCallback?.Invoke(0, ".", count % DIRECTORIES_PER_LINE == 0);
|
||||
}), cancellationToken);
|
||||
{
|
||||
count++;
|
||||
progressCallback?.Invoke(0, ".", count % DIRECTORIES_PER_LINE == 0);
|
||||
}), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -840,7 +866,7 @@ namespace ServerManagerTool.Lib
|
|||
// check if the mod needs to be copied, or force the copy.
|
||||
if (Config.Default.ServerUpdate_ForceCopyMods)
|
||||
{
|
||||
progressCallback?.Invoke(0, $"{SteamCmdUpdater.OUTPUT_PREFIX} Forcing mod copy - ASM setting is TRUE.");
|
||||
progressCallback?.Invoke(0, $"{SteamCmdUpdater.OUTPUT_PREFIX} Forcing mod copy - Server Manager setting is TRUE.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using NLog;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using QueryMaster;
|
||||
using ServerManagerTool.Common.Enums;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
|
|
@ -22,15 +24,15 @@ namespace ServerManagerTool.Lib
|
|||
private readonly ActionBlock<Func<Task>> _eventQueue;
|
||||
private readonly Dictionary<string, DateTime> _nextExternalStatusQuery = new Dictionary<string, DateTime>();
|
||||
|
||||
static ServerStatusWatcher()
|
||||
{
|
||||
Instance = new ServerStatusWatcher();
|
||||
}
|
||||
|
||||
private ServerStatusWatcher()
|
||||
{
|
||||
_eventQueue = new ActionBlock<Func<Task>>(async f => await f.Invoke(), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 });
|
||||
_eventQueue.Post(DoLocalUpdate);
|
||||
}
|
||||
|
||||
static ServerStatusWatcher()
|
||||
{
|
||||
ServerStatusWatcher.Instance = new ServerStatusWatcher();
|
||||
_eventQueue.Post(DoUpdateAsync);
|
||||
}
|
||||
|
||||
public static ServerStatusWatcher Instance
|
||||
|
|
@ -84,10 +86,134 @@ namespace ServerManagerTool.Lib
|
|||
return registration;
|
||||
}
|
||||
|
||||
private async Task DoUpdateAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var registration in _serverRegistrations)
|
||||
{
|
||||
var statusUpdate = new ServerStatusUpdate();
|
||||
|
||||
try
|
||||
{
|
||||
Logger.Info($"{nameof(DoUpdateAsync)} Start: {registration.LocalEndpoint}, {registration.PublicEndpoint}");
|
||||
statusUpdate = await DoServerStatusUpdateAsync(registration);
|
||||
|
||||
PostServerStatusUpdate(registration, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// We don't want to stop other registration queries or break the ActionBlock
|
||||
Logger.Error($"{nameof(DoUpdateAsync)} - Exception in local update. {ex.Message}\r\n{ex.StackTrace}");
|
||||
Debugger.Break();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Info($"{nameof(DoUpdateAsync)} End: {registration.LocalEndpoint}, {registration.PublicEndpoint}, Status: {statusUpdate.Status}");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Task.Delay(Config.Default.ServerStatusWatcher_LocalStatusQueryDelay)
|
||||
.ContinueWith(_ => _eventQueue.Post(DoUpdateAsync))
|
||||
.DoNotWait();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ServerStatusUpdate> DoServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
|
||||
{
|
||||
var registrationKey = registration.PublicEndpoint.ToString();
|
||||
|
||||
//
|
||||
// First check the process status
|
||||
//
|
||||
var processStatus = GetServerProcessStatus(registration, out Process process);
|
||||
switch (processStatus)
|
||||
{
|
||||
case ServerProcessStatus.NotInstalled:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.NotInstalled };
|
||||
|
||||
case ServerProcessStatus.Stopped:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.Stopped };
|
||||
|
||||
case ServerProcessStatus.Unknown:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.Unknown };
|
||||
|
||||
case ServerProcessStatus.Running:
|
||||
break;
|
||||
|
||||
default:
|
||||
Debugger.Break();
|
||||
break;
|
||||
}
|
||||
|
||||
var currentStatus = WatcherServerStatus.Initializing;
|
||||
|
||||
//
|
||||
// If the process was running do we then perform network checks.
|
||||
//
|
||||
Logger.Info($"{nameof(DoServerStatusUpdateAsync)} Checking server local network status at {registration.LocalEndpoint}");
|
||||
|
||||
// get the server information direct from the server using local connection.
|
||||
var serverStatus = GetLocalNetworkStatus(registration.LocalEndpoint, out ServerInfo localInfo, out int onlinePlayerCount);
|
||||
|
||||
if (serverStatus)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.RunningLocalCheck;
|
||||
|
||||
//
|
||||
// Now that it's running, we can check the publication status.
|
||||
//
|
||||
Logger.Info($"{nameof(DoServerStatusUpdateAsync)} Checking server public (directly) status at {registration.PublicEndpoint}");
|
||||
|
||||
// get the server information direct from the server using public connection.
|
||||
serverStatus = GetPublicNetworkStatusDirectly(registration.PublicEndpoint);
|
||||
|
||||
// check if the server returned the information.
|
||||
if (!serverStatus)
|
||||
{
|
||||
// server did not return any information
|
||||
var nextExternalStatusQuery = _nextExternalStatusQuery.ContainsKey(registrationKey) ? _nextExternalStatusQuery[registrationKey] : DateTime.MinValue;
|
||||
if (DateTime.Now >= nextExternalStatusQuery)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.RunningExternalCheck;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerStatusUrlFormat))
|
||||
{
|
||||
Logger.Info($"{nameof(DoServerStatusUpdateAsync)} Checking server public (via api) status at {registration.PublicEndpoint}");
|
||||
|
||||
// get the server information direct from the server using external connection.
|
||||
var uri = new Uri(string.Format(Config.Default.ServerStatusUrlFormat, Config.Default.ServerManagerCode, App.Instance.Version, registration.PublicEndpoint.Address, registration.PublicEndpoint.Port));
|
||||
serverStatus = await GetPublicNetworkStatusViaAPIAsync(uri, registration.PublicEndpoint);
|
||||
}
|
||||
|
||||
_nextExternalStatusQuery[registrationKey] = DateTime.Now.AddMilliseconds(Config.Default.ServerStatusWatcher_RemoteStatusQueryDelay);
|
||||
}
|
||||
}
|
||||
|
||||
// check if the server returned the information.
|
||||
if (serverStatus)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.Published;
|
||||
}
|
||||
}
|
||||
|
||||
var statusUpdate = new ServerStatusUpdate
|
||||
{
|
||||
Process = process,
|
||||
Status = currentStatus,
|
||||
ServerInfo = localInfo,
|
||||
OnlinePlayerCount = onlinePlayerCount,
|
||||
};
|
||||
|
||||
return await Task.FromResult(statusUpdate);
|
||||
}
|
||||
|
||||
private static ServerProcessStatus GetServerProcessStatus(ServerStatusUpdateRegistration updateContext, out Process serverProcess)
|
||||
{
|
||||
serverProcess = null;
|
||||
if (String.IsNullOrWhiteSpace(updateContext.InstallDirectory))
|
||||
if (string.IsNullOrWhiteSpace(updateContext.InstallDirectory))
|
||||
{
|
||||
return ServerProcessStatus.NotInstalled;
|
||||
}
|
||||
|
|
@ -107,19 +233,19 @@ namespace ServerManagerTool.Lib
|
|||
{
|
||||
var commandLine = ProcessUtils.GetCommandLineForProcess(process.Id)?.ToLower();
|
||||
|
||||
if (commandLine != null &&
|
||||
if (commandLine != null &&
|
||||
(commandLine.StartsWith(serverExePath, StringComparison.OrdinalIgnoreCase) || commandLine.StartsWith($"\"{serverExePath}\"", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
// Does this match our server exe and port?
|
||||
var serverArgMatch = String.Format(Config.Default.ServerCommandLineArgsMatchFormat, updateContext.LocalEndpoint.Port).ToLower();
|
||||
var serverArgMatch = string.Format(Config.Default.ServerCommandLineArgsMatchFormat, updateContext.LocalEndpoint.Port).ToLower();
|
||||
if (commandLine.Contains(serverArgMatch))
|
||||
{
|
||||
// Was an IP set on it?
|
||||
var anyIpArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, String.Empty).ToLower();
|
||||
var anyIpArgMatch = string.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, string.Empty).ToLower();
|
||||
if (commandLine.Contains(anyIpArgMatch))
|
||||
{
|
||||
// If we have a specific IP, check for it.
|
||||
var ipArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, updateContext.LocalEndpoint.Address.ToString()).ToLower();
|
||||
var ipArgMatch = string.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, updateContext.LocalEndpoint.Address.ToString()).ToLower();
|
||||
if (!commandLine.Contains(ipArgMatch))
|
||||
{
|
||||
// Specific IP set didn't match
|
||||
|
|
@ -151,160 +277,20 @@ namespace ServerManagerTool.Lib
|
|||
return ServerProcessStatus.Stopped;
|
||||
}
|
||||
|
||||
private async Task DoLocalUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var registration in this._serverRegistrations)
|
||||
{
|
||||
ServerStatusUpdate statusUpdate = new ServerStatusUpdate();
|
||||
try
|
||||
{
|
||||
Logger.Info($"{nameof(DoLocalUpdate)} Start: {registration.LocalEndpoint}");
|
||||
statusUpdate = await GenerateServerStatusUpdateAsync(registration);
|
||||
|
||||
PostServerStatusUpdate(registration, registration.UpdateCallback, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// We don't want to stop other registration queries or break the ActionBlock
|
||||
Logger.Error($"{nameof(DoLocalUpdate)} - Exception in local update. {ex.Message}\r\n{ex.StackTrace}");
|
||||
Debugger.Break();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Info($"{nameof(DoLocalUpdate)} End: {registration.LocalEndpoint}: {statusUpdate.Status}");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Task.Delay(Config.Default.ServerStatusWatcher_LocalStatusQueryDelay).ContinueWith(_ => _eventQueue.Post(DoLocalUpdate)).DoNotWait();
|
||||
}
|
||||
}
|
||||
|
||||
private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, Action<IAsyncDisposable, ServerStatusUpdate> callback, ServerStatusUpdate statusUpdate)
|
||||
{
|
||||
_eventQueue.Post(() =>
|
||||
{
|
||||
if (this._serverRegistrations.Contains(registration))
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(registration, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugUtils.WriteFormatThreadSafeAsync("Exception during local status update callback: {0}\n{1}", ex.Message, ex.StackTrace).DoNotWait();
|
||||
}
|
||||
}
|
||||
return TaskUtils.FinishedTask;
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<ServerStatusUpdate> GenerateServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
|
||||
{
|
||||
var registrationKey = registration.PublicEndpoint.ToString();
|
||||
|
||||
//
|
||||
// First check the process status
|
||||
//
|
||||
var processStatus = GetServerProcessStatus(registration, out Process process);
|
||||
switch(processStatus)
|
||||
{
|
||||
case ServerProcessStatus.NotInstalled:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.NotInstalled };
|
||||
|
||||
case ServerProcessStatus.Stopped:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.Stopped };
|
||||
|
||||
case ServerProcessStatus.Unknown:
|
||||
return new ServerStatusUpdate { Status = WatcherServerStatus.Unknown };
|
||||
|
||||
case ServerProcessStatus.Running:
|
||||
break;
|
||||
|
||||
default:
|
||||
Debugger.Break();
|
||||
break;
|
||||
}
|
||||
|
||||
var currentStatus = WatcherServerStatus.Initializing;
|
||||
|
||||
//
|
||||
// If the process was running do we then perform network checks.
|
||||
//
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server local network status at {registration.LocalEndpoint}");
|
||||
|
||||
// get the server information direct from the server using local connection.
|
||||
GetLocalNetworkStatus(registration.LocalEndpoint, out QueryMaster.ServerInfo localInfo, out int onlinePlayerCount);
|
||||
|
||||
if (localInfo != null)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.RunningLocalCheck;
|
||||
|
||||
//
|
||||
// Now that it's running, we can check the publication status.
|
||||
//
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public (directly) status at {registration.PublicEndpoint}");
|
||||
|
||||
// get the server information direct from the server using public connection.
|
||||
var serverStatus = CheckServerStatusDirect(registration.PublicEndpoint);
|
||||
// check if the server returned the information.
|
||||
if (!serverStatus)
|
||||
{
|
||||
// server did not return any information
|
||||
var nextExternalStatusQuery = _nextExternalStatusQuery.ContainsKey(registrationKey) ? _nextExternalStatusQuery[registrationKey] : DateTime.MinValue;
|
||||
if (DateTime.Now >= nextExternalStatusQuery)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.RunningExternalCheck;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerStatusUrlFormat))
|
||||
{
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public (via api) status at {registration.PublicEndpoint}");
|
||||
|
||||
// get the server information direct from the server using external connection.
|
||||
var uri = new Uri(string.Format(Config.Default.ServerStatusUrlFormat, Config.Default.ServerManagerCode, App.Instance.Version, registration.PublicEndpoint.Address, registration.PublicEndpoint.Port));
|
||||
serverStatus = await NetworkUtils.CheckServerStatusViaAPI(uri, registration.PublicEndpoint);
|
||||
}
|
||||
|
||||
_nextExternalStatusQuery[registrationKey] = DateTime.Now.AddMilliseconds(Config.Default.ServerStatusWatcher_RemoteStatusQueryDelay);
|
||||
}
|
||||
}
|
||||
|
||||
// check if the server returned the information.
|
||||
if (serverStatus)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.Published;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var statusUpdate = new ServerStatusUpdate
|
||||
{
|
||||
Process = process,
|
||||
Status = currentStatus,
|
||||
ServerInfo = localInfo,
|
||||
OnlinePlayerCount = onlinePlayerCount
|
||||
};
|
||||
|
||||
return await Task.FromResult(statusUpdate);
|
||||
}
|
||||
|
||||
private static bool GetLocalNetworkStatus(IPEndPoint endpoint, out QueryMaster.ServerInfo serverInfo, out int onlinePlayerCount)
|
||||
private static bool GetLocalNetworkStatus(IPEndPoint endpoint, out ServerInfo serverInfo, out int onlinePlayerCount)
|
||||
{
|
||||
serverInfo = null;
|
||||
onlinePlayerCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
|
||||
using (var server = ServerQuery.GetServerInstance(EngineType.Source, endpoint))
|
||||
{
|
||||
try
|
||||
{
|
||||
serverInfo = server?.GetInfo();
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception)
|
||||
{
|
||||
serverInfo = null;
|
||||
}
|
||||
|
|
@ -314,28 +300,34 @@ namespace ServerManagerTool.Lib
|
|||
var playerInfo = server?.GetPlayers()?.Where(p => !string.IsNullOrWhiteSpace(p.Name?.Trim()));
|
||||
onlinePlayerCount = playerInfo?.Count() ?? 0;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception)
|
||||
{
|
||||
onlinePlayerCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return serverInfo != null;
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(GetLocalNetworkStatus)} failed: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
// Common when the server is unreachable. Ignore it.
|
||||
Logger.Debug($"{nameof(GetLocalNetworkStatus)} - Failed checking local status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(GetLocalNetworkStatus)} - Failed checking local status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool CheckServerStatusDirect(IPEndPoint endpoint)
|
||||
private static bool GetPublicNetworkStatusDirectly(IPEndPoint endpoint)
|
||||
{
|
||||
ServerInfo serverInfo;
|
||||
|
||||
try
|
||||
{
|
||||
QueryMaster.ServerInfo serverInfo;
|
||||
|
||||
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
|
||||
using (var server = ServerQuery.GetServerInstance(EngineType.Source, endpoint))
|
||||
{
|
||||
serverInfo = server.GetInfo();
|
||||
}
|
||||
|
|
@ -344,9 +336,69 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(CheckServerStatusDirect)} - Failed checking status direct for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
return false;
|
||||
Logger.Debug($"{nameof(GetPublicNetworkStatusDirectly)} - Failed checking public status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async Task<bool> GetPublicNetworkStatusViaAPIAsync(Uri uri, IPEndPoint endpoint)
|
||||
{
|
||||
try
|
||||
{
|
||||
string jsonString;
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
jsonString = await client.DownloadStringTaskAsync(uri);
|
||||
}
|
||||
|
||||
if (jsonString == null)
|
||||
{
|
||||
Logger.Debug($"Server info request returned null string for {endpoint.Address}:{endpoint.Port}");
|
||||
return false;
|
||||
}
|
||||
|
||||
JObject query = JObject.Parse(jsonString);
|
||||
if (query == null)
|
||||
{
|
||||
Logger.Debug($"Server info request failed to parse for {endpoint.Address}:{endpoint.Port} - '{jsonString}'");
|
||||
return false;
|
||||
}
|
||||
|
||||
var available = query.SelectToken("available");
|
||||
if (available == null)
|
||||
{
|
||||
Logger.Debug($"Server at {endpoint.Address}:{endpoint.Port} returned no availability.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool)available;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(GetPublicNetworkStatusViaAPIAsync)} - Failed checking public status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, ServerStatusUpdate statusUpdate)
|
||||
{
|
||||
_eventQueue.Post(() =>
|
||||
{
|
||||
if (_serverRegistrations.Contains(registration))
|
||||
{
|
||||
try
|
||||
{
|
||||
registration.UpdateCallback(registration, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugUtils.WriteFormatThreadSafeAsync("Exception during server status update callback: {0}\n{1}", ex.Message, ex.StackTrace).DoNotWait();
|
||||
}
|
||||
}
|
||||
return TaskUtils.FinishedTask;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -425,12 +425,19 @@
|
|||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.Unavailable}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Unavailable}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_UnavailableTootip}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.Waiting}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Waiting}"/>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.LocalOnly}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_LocalOnly}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_LocalOnlyTootip}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.PublicOnly}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_PublicOnly}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_PublicOnlyTootip}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.Available}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Available}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_AvailableTootip}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
<entry>
|
||||
<id>urn:uuid:FF41F7AB-66B0-4504-9F2C-2E1325DB50E2</id>
|
||||
<title>1.1.434 (1.1.434.2)</title>
|
||||
<summary>1.1.434.2</summary>
|
||||
<title>1.1.434 (1.1.434.3)</title>
|
||||
<summary>1.1.434.3</summary>
|
||||
<link href="" />
|
||||
<updated>2022-06-22T00:00:00Z</updated>
|
||||
<content type="xhtml">
|
||||
|
|
@ -19,9 +19,10 @@
|
|||
<u style="font-size: .9em;">CHANGE</u>
|
||||
<br/>
|
||||
<ul>
|
||||
<li>3rd Party Libraries - updated all library to latest versions.</li>
|
||||
<li>Availability Status - Changed the Waiting for Publication status into two new statuses, to clarify the issue.</li>
|
||||
<li>Rules Section - Fjordur Settings - added checkbox to enable/disable settings.</li>
|
||||
<li>Rules Section - Ragnarok Settings - added settings for Ragnarok, located at the bottom of the section.</li>
|
||||
<li>3rd Party Libraries - updated all library to latest versions.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,29 @@
|
|||
<link href="http://arkservermanager.freeforums.net/" />
|
||||
<updated>2022-06-22T00:00:00Z</updated>
|
||||
|
||||
<entry>
|
||||
<id>urn:uuid:F3965FC7-685F-47DF-9E5B-3BA4D928127F</id>
|
||||
<title>1.1.434 (1.1.434.3)</title>
|
||||
<summary>1.1.434.2</summary>
|
||||
<link href="" />
|
||||
<updated>2022-06-22T00:00:00Z</updated>
|
||||
<content type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
|
||||
<p>
|
||||
<u style="font-size: .9em;">CHANGE</u>
|
||||
<br/>
|
||||
<ul>
|
||||
<li>Availability Status - Changed the Waiting for Publication status into two new statuses, to clarify the issue.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</content>
|
||||
<author>
|
||||
<name>bletch</name>
|
||||
<email>bletch1971@hotmail.com</email>
|
||||
</author>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<id>urn:uuid:F3965FC7-685F-47DF-9E5B-3BA4D928127F</id>
|
||||
<title>1.1.434 (1.1.434.2)</title>
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@
|
|||
<setting name="ServerCommandLineArgsIPMatchFormat" serializeAs="String">
|
||||
<value>-MultiHome={0}</value>
|
||||
</setting>
|
||||
<setting name="ServerCommandLineArgsPortMatchFormat" serializeAs="String">
|
||||
<setting name="ServerCommandLineArgsMatchFormat" serializeAs="String">
|
||||
<value>-QueryPort={0}</value>
|
||||
</setting>
|
||||
<setting name="GameDataRelativePath" serializeAs="String">
|
||||
|
|
|
|||
|
|
@ -672,12 +672,12 @@ namespace ServerManagerTool
|
|||
if (Config.Default.LoggingEnabled)
|
||||
{
|
||||
while (!LogManager.IsLoggingEnabled())
|
||||
LogManager.EnableLogging();
|
||||
LogManager.ResumeLogging();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (LogManager.IsLoggingEnabled())
|
||||
LogManager.DisableLogging();
|
||||
LogManager.SuspendLogging();
|
||||
}
|
||||
|
||||
Debug.WriteLine($"Logging Enabled: {LogManager.IsLoggingEnabled()}");
|
||||
|
|
|
|||
4
src/ConanServerManager/Config.Designer.cs
generated
4
src/ConanServerManager/Config.Designer.cs
generated
|
|
@ -1370,9 +1370,9 @@ namespace ServerManagerTool {
|
|||
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("-QueryPort={0}")]
|
||||
public string ServerCommandLineArgsPortMatchFormat {
|
||||
public string ServerCommandLineArgsMatchFormat {
|
||||
get {
|
||||
return ((string)(this["ServerCommandLineArgsPortMatchFormat"]));
|
||||
return ((string)(this["ServerCommandLineArgsMatchFormat"]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@
|
|||
<Setting Name="ServerCommandLineArgsIPMatchFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">-MultiHome={0}</Value>
|
||||
</Setting>
|
||||
<Setting Name="ServerCommandLineArgsPortMatchFormat" Type="System.String" Scope="Application">
|
||||
<Setting Name="ServerCommandLineArgsMatchFormat" Type="System.String" Scope="Application">
|
||||
<Value Profile="(Default)">-QueryPort={0}</Value>
|
||||
</Setting>
|
||||
<Setting Name="BackupPath" Type="System.String" Scope="User">
|
||||
|
|
|
|||
|
|
@ -1012,14 +1012,19 @@
|
|||
<sys:String x:Key="ServerSettings_LastStartedLabel">Last Start Time:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AvailabilityLabel">Availability:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_AvailabilityTooltip">The status of the server on Steam.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Unknown">Unknown</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_SetPublicIP">Set Public IP</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Unavailable">Unavailable</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Waiting">Waiting for publication</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Available">Available</sys:String>
|
||||
<sys:String x:Key="ServerSettings_PlayersLabel">Players:</sys:String>
|
||||
<sys:String x:Key="ServerSettings_PlayersTooltip">The current number of players connected to the server.</sys:String>
|
||||
|
||||
<sys:String x:Key="ServerSettings_Availability_Unknown">Unknown</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Unavailable">Unavailable</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_UnavailableTootip">Server in not accessible</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_LocalOnly">LAN Only</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_LocalOnlyTootip">Server accessible via Local IP only. Port Forwarding, Firewall or CGNAT etc are preventing public access.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_PublicOnly">Available - No Loopback</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_PublicOnlyTootip">Server accessible via Local IP and Public IP, loopback not available. Server is public but Public IP not accessible via LAN.</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_Available">Available</sys:String>
|
||||
<sys:String x:Key="ServerSettings_Availability_AvailableTootip">Server accessible via Local IP and Public IP</sys:String>
|
||||
|
||||
<sys:String x:Key="ServerSettings_RuntimeStatusInitializingLabel">Initializing</sys:String>
|
||||
<sys:String x:Key="ServerSettings_RuntimeStatusRunningLabel">Running</sys:String>
|
||||
<sys:String x:Key="ServerSettings_RuntimeStatusStoppedLabel">Stopped</sys:String>
|
||||
|
|
|
|||
|
|
@ -875,7 +875,7 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
serverArgs.Append($" -Port={this.ServerPort}");
|
||||
serverArgs.Append(" ");
|
||||
serverArgs.AppendFormat(Config.Default.ServerCommandLineArgsPortMatchFormat, this.QueryPort);
|
||||
serverArgs.AppendFormat(Config.Default.ServerCommandLineArgsMatchFormat, this.QueryPort);
|
||||
if (this.RconEnabled)
|
||||
{
|
||||
serverArgs.AppendFormat($" -RconPort={this.RconPort}");
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ namespace ServerManagerTool.Lib
|
|||
//
|
||||
// Get the local endpoint for querying the local network
|
||||
//
|
||||
if (!ushort.TryParse(this.ProfileSnapshot.QueryPort.ToString(), out ushort port))
|
||||
if (!ushort.TryParse(this.ProfileSnapshot.QueryPort.ToString(), out _))
|
||||
{
|
||||
_logger.Error($"Port is out of range ({this.ProfileSnapshot.QueryPort})");
|
||||
return;
|
||||
|
|
@ -205,7 +205,7 @@ namespace ServerManagerTool.Lib
|
|||
// Get the public endpoint for querying Steam
|
||||
//
|
||||
steamServerQueryEndPoint = null;
|
||||
if (!String.IsNullOrWhiteSpace(Config.Default.MachinePublicIP))
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.MachinePublicIP))
|
||||
{
|
||||
if (IPAddress.TryParse(Config.Default.MachinePublicIP, out IPAddress steamServerIpAddress))
|
||||
{
|
||||
|
|
@ -237,7 +237,7 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
private void ProcessStatusUpdate(IAsyncDisposable registration, ServerStatusUpdate update)
|
||||
{
|
||||
if(!Object.ReferenceEquals(registration, this.updateRegistration))
|
||||
if (!ReferenceEquals(registration, this.updateRegistration))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -245,64 +245,90 @@ namespace ServerManagerTool.Lib
|
|||
TaskUtils.RunOnUIThreadAsync(() =>
|
||||
{
|
||||
var oldStatus = this.Status;
|
||||
var oldAvailability = this.Availability;
|
||||
|
||||
switch (update.Status)
|
||||
{
|
||||
case WatcherServerStatus.Unknown:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Unknown, AvailabilityStatus.Unknown, false);
|
||||
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.NotInstalled:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Uninstalled, AvailabilityStatus.Unavailable, false);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Initializing:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Initializing, AvailabilityStatus.Unavailable, oldStatus != ServerStatus.Initializing && oldStatus != ServerStatus.Unknown);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Stopped:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Stopped, AvailabilityStatus.Unavailable, oldStatus == ServerStatus.Initializing || oldStatus == ServerStatus.Running || oldStatus == ServerStatus.Stopping);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Unknown:
|
||||
if (oldStatus != ServerStatus.Updating)
|
||||
UpdateServerStatus(ServerStatus.Unknown, AvailabilityStatus.Unknown, false);
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
case WatcherServerStatus.Initializing:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
UpdateServerStatus(ServerStatus.Initializing, AvailabilityStatus.Unavailable, oldStatus != ServerStatus.Initializing && oldStatus != ServerStatus.Unknown);
|
||||
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.RunningLocalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
{
|
||||
UpdateServerStatus(ServerStatus.Running, this.Availability != AvailabilityStatus.Available ? AvailabilityStatus.Waiting : this.Availability, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
UpdateServerStatus(ServerStatus.Running, oldAvailability != AvailabilityStatus.Available ? AvailabilityStatus.LocalOnly : AvailabilityStatus.Available, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Start();
|
||||
}
|
||||
else
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
{
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.RunningExternalCheck:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
{
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.Waiting, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.PublicOnly, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Start();
|
||||
}
|
||||
else
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
{
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case WatcherServerStatus.Published:
|
||||
if (oldStatus != ServerStatus.Stopping)
|
||||
{
|
||||
UpdateServerStatus(ServerStatus.Running, AvailabilityStatus.Available, oldStatus != ServerStatus.Running && oldStatus != ServerStatus.Unknown);
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Start();
|
||||
|
||||
if (this.ProfileSnapshot.MOTDIntervalEnabled && this.motdIntervalTimer != null && !this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Start();
|
||||
}
|
||||
else
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
{
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled) this.motdIntervalTimer.Stop();
|
||||
if (this.motdIntervalTimer != null && this.motdIntervalTimer.Enabled)
|
||||
this.motdIntervalTimer.Stop();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -322,7 +348,7 @@ namespace ServerManagerTool.Lib
|
|||
if (match.Success && match.Groups.Count >= 2)
|
||||
{
|
||||
var serverVersion = $"{version}.{match.Groups[1].Value}";
|
||||
if (!String.IsNullOrWhiteSpace(serverVersion) && Version.TryParse(serverVersion, out Version temp))
|
||||
if (!string.IsNullOrWhiteSpace(serverVersion) && Version.TryParse(serverVersion, out Version temp))
|
||||
{
|
||||
this.Version = temp;
|
||||
}
|
||||
|
|
@ -385,7 +411,7 @@ namespace ServerManagerTool.Lib
|
|||
if (localServerQueryEndPoint == null || steamServerQueryEndPoint == null)
|
||||
return;
|
||||
|
||||
this.updateRegistration = ServerStatusWatcher.Instance.RegisterForUpdates(this.ProfileSnapshot.InstallDirectory, this.ProfileSnapshot.ProfileId, this.ProfileSnapshot.GameFile, localServerQueryEndPoint, steamServerQueryEndPoint, ProcessStatusUpdate);
|
||||
this.updateRegistration = ServerStatusWatcher.Instance.RegisterForUpdates(this.ProfileSnapshot.InstallDirectory, this.ProfileSnapshot.ProfileId, localServerQueryEndPoint, steamServerQueryEndPoint, ProcessStatusUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using NLog;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using QueryMaster;
|
||||
using ServerManagerTool.Common.Enums;
|
||||
using ServerManagerTool.Common.Utils;
|
||||
using ServerManagerTool.Enums;
|
||||
|
|
@ -30,7 +32,7 @@ namespace ServerManagerTool.Lib
|
|||
private ServerStatusWatcher()
|
||||
{
|
||||
_eventQueue = new ActionBlock<Func<Task>>(async f => await f.Invoke(), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 });
|
||||
_eventQueue.Post(DoLocalUpdate);
|
||||
_eventQueue.Post(DoUpdateAsync);
|
||||
}
|
||||
|
||||
public static ServerStatusWatcher Instance
|
||||
|
|
@ -39,7 +41,7 @@ namespace ServerManagerTool.Lib
|
|||
private set;
|
||||
}
|
||||
|
||||
public IAsyncDisposable RegisterForUpdates(string installDirectory, string profileId, string gameFile, IPEndPoint localEndpoint, IPEndPoint steamEndpoint, Action<IAsyncDisposable, ServerStatusUpdate> updateCallback)
|
||||
public IAsyncDisposable RegisterForUpdates(string installDirectory, string profileId, IPEndPoint localEndpoint, IPEndPoint steamEndpoint, Action<IAsyncDisposable, ServerStatusUpdate> updateCallback)
|
||||
{
|
||||
var registration = new ServerStatusUpdateRegistration
|
||||
{
|
||||
|
|
@ -84,125 +86,42 @@ namespace ServerManagerTool.Lib
|
|||
return registration;
|
||||
}
|
||||
|
||||
private static ServerProcessStatus GetServerProcessStatus(ServerStatusUpdateRegistration updateContext, out Process serverProcess)
|
||||
{
|
||||
serverProcess = null;
|
||||
if (String.IsNullOrWhiteSpace(updateContext.InstallDirectory))
|
||||
{
|
||||
return ServerProcessStatus.NotInstalled;
|
||||
}
|
||||
|
||||
var serverExePath = Path.Combine(updateContext.InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerExeFile);
|
||||
if(!File.Exists(serverExePath))
|
||||
{
|
||||
return ServerProcessStatus.NotInstalled;
|
||||
}
|
||||
|
||||
//
|
||||
// The server appears to be installed, now determine if it is running or stopped.
|
||||
//
|
||||
try
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName(Config.Default.ServerProcessName))
|
||||
{
|
||||
var commandLine = ProcessUtils.GetCommandLineForProcess(process.Id)?.ToLower();
|
||||
|
||||
if (commandLine != null &&
|
||||
(commandLine.StartsWith(serverExePath, StringComparison.OrdinalIgnoreCase) || commandLine.StartsWith($"\"{serverExePath}\"", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
// Does this match our server exe and port?
|
||||
var serverArgMatch = String.Format(Config.Default.ServerCommandLineArgsPortMatchFormat, updateContext.LocalEndpoint.Port).ToLower();
|
||||
if (commandLine.Contains(serverArgMatch))
|
||||
{
|
||||
// Was an IP set on it?
|
||||
var anyIpArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, String.Empty).ToLower();
|
||||
if (commandLine.Contains(anyIpArgMatch))
|
||||
{
|
||||
// If we have a specific IP, check for it.
|
||||
var ipArgMatch = String.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, updateContext.LocalEndpoint.Address.ToString()).ToLower();
|
||||
if (!commandLine.Contains(ipArgMatch))
|
||||
{
|
||||
// Specific IP set didn't match
|
||||
continue;
|
||||
}
|
||||
|
||||
// Specific IP matched
|
||||
}
|
||||
|
||||
// Either specific IP matched or no specific IP was set and we will claim this is ours.
|
||||
|
||||
process.EnableRaisingEvents = true;
|
||||
if (process.HasExited)
|
||||
{
|
||||
return ServerProcessStatus.Stopped;
|
||||
}
|
||||
|
||||
serverProcess = process;
|
||||
return ServerProcessStatus.Running;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger.Error($"{nameof(GetServerProcessStatus)}. {ex.Message}\r\n{ex.StackTrace}");
|
||||
}
|
||||
|
||||
return ServerProcessStatus.Stopped;
|
||||
}
|
||||
|
||||
private async Task DoLocalUpdate()
|
||||
private async Task DoUpdateAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var registration in this._serverRegistrations)
|
||||
foreach (var registration in _serverRegistrations)
|
||||
{
|
||||
ServerStatusUpdate statusUpdate = new ServerStatusUpdate();
|
||||
var statusUpdate = new ServerStatusUpdate();
|
||||
|
||||
try
|
||||
{
|
||||
Logger.Info($"{nameof(DoLocalUpdate)} Start: {registration.LocalEndpoint}");
|
||||
statusUpdate = await GenerateServerStatusUpdateAsync(registration);
|
||||
Logger.Info($"{nameof(DoUpdateAsync)} Start: {registration.LocalEndpoint}, {registration.PublicEndpoint}");
|
||||
statusUpdate = await DoServerStatusUpdateAsync(registration);
|
||||
|
||||
PostServerStatusUpdate(registration, registration.UpdateCallback, statusUpdate);
|
||||
PostServerStatusUpdate(registration, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// We don't want to stop other registration queries or break the ActionBlock
|
||||
Logger.Error($"{nameof(DoLocalUpdate)} - Exception in local update. {ex.Message}\r\n{ex.StackTrace}");
|
||||
Logger.Error($"{nameof(DoUpdateAsync)} - Exception in local update. {ex.Message}\r\n{ex.StackTrace}");
|
||||
Debugger.Break();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Info($"{nameof(DoLocalUpdate)} End: {registration.LocalEndpoint}: {statusUpdate.Status}");
|
||||
Logger.Info($"{nameof(DoUpdateAsync)} End: {registration.LocalEndpoint}, {registration.PublicEndpoint}, Status: {statusUpdate.Status}");
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Task.Delay(Config.Default.ServerStatusWatcher_LocalStatusQueryDelay).ContinueWith(_ => _eventQueue.Post(DoLocalUpdate)).DoNotWait();
|
||||
Task.Delay(Config.Default.ServerStatusWatcher_LocalStatusQueryDelay)
|
||||
.ContinueWith(_ => _eventQueue.Post(DoUpdateAsync))
|
||||
.DoNotWait();
|
||||
}
|
||||
}
|
||||
|
||||
private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, Action<IAsyncDisposable, ServerStatusUpdate> callback, ServerStatusUpdate statusUpdate)
|
||||
{
|
||||
_eventQueue.Post(() =>
|
||||
{
|
||||
if (this._serverRegistrations.Contains(registration))
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(registration, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugUtils.WriteFormatThreadSafeAsync("Exception during local status update callback: {0}\n{1}", ex.Message, ex.StackTrace).DoNotWait();
|
||||
}
|
||||
}
|
||||
return TaskUtils.FinishedTask;
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<ServerStatusUpdate> GenerateServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
|
||||
private async Task<ServerStatusUpdate> DoServerStatusUpdateAsync(ServerStatusUpdateRegistration registration)
|
||||
{
|
||||
var registrationKey = registration.PublicEndpoint.ToString();
|
||||
|
||||
|
|
@ -234,22 +153,23 @@ namespace ServerManagerTool.Lib
|
|||
//
|
||||
// If the process was running do we then perform network checks.
|
||||
//
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server local network status at {registration.LocalEndpoint}");
|
||||
Logger.Info($"{nameof(DoServerStatusUpdateAsync)} Checking server local network status at {registration.LocalEndpoint}");
|
||||
|
||||
// get the server information direct from the server using local connection.
|
||||
GetLocalNetworkStatus(registration.LocalEndpoint, out QueryMaster.ServerInfo localInfo, out int onlinePlayerCount);
|
||||
var serverStatus = GetLocalNetworkStatus(registration.LocalEndpoint, out ServerInfo localInfo, out int onlinePlayerCount);
|
||||
|
||||
if (localInfo != null)
|
||||
if (serverStatus)
|
||||
{
|
||||
currentStatus = WatcherServerStatus.RunningLocalCheck;
|
||||
|
||||
//
|
||||
// Now that it's running, we can check the publication status.
|
||||
//
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public (directly) status at {registration.PublicEndpoint}");
|
||||
Logger.Info($"{nameof(DoServerStatusUpdateAsync)} Checking server public (directly) status at {registration.PublicEndpoint}");
|
||||
|
||||
// get the server information direct from the server using public connection.
|
||||
var serverStatus = CheckServerStatusDirect(registration.PublicEndpoint);
|
||||
serverStatus = GetPublicNetworkStatusDirectly(registration.PublicEndpoint);
|
||||
|
||||
// check if the server returned the information.
|
||||
if (!serverStatus)
|
||||
{
|
||||
|
|
@ -261,11 +181,11 @@ namespace ServerManagerTool.Lib
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(Config.Default.ServerStatusUrlFormat))
|
||||
{
|
||||
Logger.Info($"{nameof(GenerateServerStatusUpdateAsync)} Checking server public (via api) status at {registration.PublicEndpoint}");
|
||||
Logger.Info($"{nameof(DoServerStatusUpdateAsync)} Checking server public (via api) status at {registration.PublicEndpoint}");
|
||||
|
||||
// get the server information direct from the server using external connection.
|
||||
var uri = new Uri(string.Format(Config.Default.ServerStatusUrlFormat, Config.Default.ServerManagerCode, App.Instance.Version, registration.PublicEndpoint.Address, registration.PublicEndpoint.Port));
|
||||
serverStatus = await NetworkUtils.CheckServerStatusViaAPI(uri, registration.PublicEndpoint);
|
||||
serverStatus = await GetPublicNetworkStatusViaAPIAsync(uri, registration.PublicEndpoint);
|
||||
}
|
||||
|
||||
_nextExternalStatusQuery[registrationKey] = DateTime.Now.AddMilliseconds(Config.Default.ServerStatusWatcher_RemoteStatusQueryDelay);
|
||||
|
|
@ -290,18 +210,85 @@ namespace ServerManagerTool.Lib
|
|||
return await Task.FromResult(statusUpdate);
|
||||
}
|
||||
|
||||
private static bool GetLocalNetworkStatus(IPEndPoint endpoint, out QueryMaster.ServerInfo serverInfo, out int onlinePlayerCount)
|
||||
private static ServerProcessStatus GetServerProcessStatus(ServerStatusUpdateRegistration updateContext, out Process serverProcess)
|
||||
{
|
||||
serverProcess = null;
|
||||
if (string.IsNullOrWhiteSpace(updateContext.InstallDirectory))
|
||||
{
|
||||
return ServerProcessStatus.NotInstalled;
|
||||
}
|
||||
|
||||
var serverExePath = Path.Combine(updateContext.InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerExeFile);
|
||||
if(!File.Exists(serverExePath))
|
||||
{
|
||||
return ServerProcessStatus.NotInstalled;
|
||||
}
|
||||
|
||||
//
|
||||
// The server appears to be installed, now determine if it is running or stopped.
|
||||
//
|
||||
try
|
||||
{
|
||||
foreach (var process in Process.GetProcessesByName(Config.Default.ServerProcessName))
|
||||
{
|
||||
var commandLine = ProcessUtils.GetCommandLineForProcess(process.Id)?.ToLower();
|
||||
|
||||
if (commandLine != null &&
|
||||
(commandLine.StartsWith(serverExePath, StringComparison.OrdinalIgnoreCase) || commandLine.StartsWith($"\"{serverExePath}\"", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
// Does this match our server exe and port?
|
||||
var serverArgMatch = string.Format(Config.Default.ServerCommandLineArgsMatchFormat, updateContext.LocalEndpoint.Port).ToLower();
|
||||
if (commandLine.Contains(serverArgMatch))
|
||||
{
|
||||
// Was an IP set on it?
|
||||
var anyIpArgMatch = string.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, string.Empty).ToLower();
|
||||
if (commandLine.Contains(anyIpArgMatch))
|
||||
{
|
||||
// If we have a specific IP, check for it.
|
||||
var ipArgMatch = string.Format(Config.Default.ServerCommandLineArgsIPMatchFormat, updateContext.LocalEndpoint.Address.ToString()).ToLower();
|
||||
if (!commandLine.Contains(ipArgMatch))
|
||||
{
|
||||
// Specific IP set didn't match
|
||||
continue;
|
||||
}
|
||||
|
||||
// Specific IP matched
|
||||
}
|
||||
|
||||
// Either specific IP matched or no specific IP was set and we will claim this is ours.
|
||||
|
||||
process.EnableRaisingEvents = true;
|
||||
if (process.HasExited)
|
||||
{
|
||||
return ServerProcessStatus.Stopped;
|
||||
}
|
||||
|
||||
serverProcess = process;
|
||||
return ServerProcessStatus.Running;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger.Error($"{nameof(GetServerProcessStatus)}. {ex.Message}\r\n{ex.StackTrace}");
|
||||
}
|
||||
|
||||
return ServerProcessStatus.Stopped;
|
||||
}
|
||||
|
||||
private static bool GetLocalNetworkStatus(IPEndPoint endpoint, out ServerInfo serverInfo, out int onlinePlayerCount)
|
||||
{
|
||||
serverInfo = null;
|
||||
onlinePlayerCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
|
||||
using (var server = ServerQuery.GetServerInstance(EngineType.Source, endpoint))
|
||||
{
|
||||
try
|
||||
{
|
||||
serverInfo = server.GetInfo();
|
||||
serverInfo = server?.GetInfo();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
|
@ -318,23 +305,29 @@ namespace ServerManagerTool.Lib
|
|||
onlinePlayerCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return serverInfo != null;
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
// Common when the server is unreachable. Log and Ignore it.
|
||||
Logger.Debug($"{nameof(GetLocalNetworkStatus)} failed: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
// Common when the server is unreachable. Ignore it.
|
||||
Logger.Debug($"{nameof(GetLocalNetworkStatus)} - Failed checking local status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(GetLocalNetworkStatus)} - Failed checking local status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool CheckServerStatusDirect(IPEndPoint endpoint)
|
||||
private static bool GetPublicNetworkStatusDirectly(IPEndPoint endpoint)
|
||||
{
|
||||
ServerInfo serverInfo;
|
||||
|
||||
try
|
||||
{
|
||||
QueryMaster.ServerInfo serverInfo;
|
||||
|
||||
using (var server = QueryMaster.ServerQuery.GetServerInstance(QueryMaster.EngineType.Source, endpoint))
|
||||
using (var server = ServerQuery.GetServerInstance(EngineType.Source, endpoint))
|
||||
{
|
||||
serverInfo = server.GetInfo();
|
||||
}
|
||||
|
|
@ -343,9 +336,69 @@ namespace ServerManagerTool.Lib
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(CheckServerStatusDirect)} - Failed checking status direct for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
return false;
|
||||
Logger.Debug($"{nameof(GetPublicNetworkStatusDirectly)} - Failed checking public status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async Task<bool> GetPublicNetworkStatusViaAPIAsync(Uri uri, IPEndPoint endpoint)
|
||||
{
|
||||
try
|
||||
{
|
||||
string jsonString;
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
jsonString = await client.DownloadStringTaskAsync(uri);
|
||||
}
|
||||
|
||||
if (jsonString == null)
|
||||
{
|
||||
Logger.Debug($"Server info request returned null string for {endpoint.Address}:{endpoint.Port}");
|
||||
return false;
|
||||
}
|
||||
|
||||
JObject query = JObject.Parse(jsonString);
|
||||
if (query == null)
|
||||
{
|
||||
Logger.Debug($"Server info request failed to parse for {endpoint.Address}:{endpoint.Port} - '{jsonString}'");
|
||||
return false;
|
||||
}
|
||||
|
||||
var available = query.SelectToken("available");
|
||||
if (available == null)
|
||||
{
|
||||
Logger.Debug($"Server at {endpoint.Address}:{endpoint.Port} returned no availability.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool)available;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug($"{nameof(GetPublicNetworkStatusViaAPIAsync)} - Failed checking public status for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void PostServerStatusUpdate(ServerStatusUpdateRegistration registration, ServerStatusUpdate statusUpdate)
|
||||
{
|
||||
_eventQueue.Post(() =>
|
||||
{
|
||||
if (_serverRegistrations.Contains(registration))
|
||||
{
|
||||
try
|
||||
{
|
||||
registration.UpdateCallback(registration, statusUpdate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DebugUtils.WriteFormatThreadSafeAsync("Exception during server status update callback: {0}\n{1}", ex.Message, ex.StackTrace).DoNotWait();
|
||||
}
|
||||
}
|
||||
return TaskUtils.FinishedTask;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,12 +285,19 @@
|
|||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.Unavailable}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Unavailable}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_UnavailableTootip}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.Waiting}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Waiting}"/>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.LocalOnly}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_LocalOnly}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_LocalOnlyTootip}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.PublicOnly}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_PublicOnly}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_PublicOnlyTootip}"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Availability}" Value="{x:Static ce:AvailabilityStatus.Available}">
|
||||
<Setter Property="Content" Value="{DynamicResource ServerSettings_Availability_Available}"/>
|
||||
<Setter Property="ToolTip" Value="{DynamicResource ServerSettings_Availability_AvailableTootip}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
<entry>
|
||||
<id>urn:uuid:CDD1853D-66EA-4649-AD24-E491D64C853E</id>
|
||||
<title>1.1.77 (1.1.77.1)</title>
|
||||
<summary>1.1.77.1</summary>
|
||||
<title>1.1.77 (1.1.77.2)</title>
|
||||
<summary>1.1.77.2</summary>
|
||||
<link href="" />
|
||||
<updated>2022-06-22T00:00:00Z</updated>
|
||||
<content type="xhtml">
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
<u style="font-size: .9em;">CHANGE</u>
|
||||
<br/>
|
||||
<ul>
|
||||
<li>Availability Status - Changed the Waiting for Publication status into two new statuses, to clarify the issue.</li>
|
||||
<li>3rd Party Libraries - updated all library to latest versions.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,29 @@
|
|||
<link href="http://servermanagers.freeforums.net/" />
|
||||
<updated>2022-06-22T00:00:00Z</updated>
|
||||
|
||||
<entry>
|
||||
<id>urn:uuid:CDD1853D-66EA-4649-AD24-E491D64C853E</id>
|
||||
<title>1.1.77 (1.1.77.2)</title>
|
||||
<summary>1.1.77.2</summary>
|
||||
<link href="" />
|
||||
<updated>2022-06-22T00:00:00Z</updated>
|
||||
<content type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: Arial, Verdana, Helvetica, Sans-Serif;font-size: .8em;">
|
||||
<p>
|
||||
<u style="font-size: .9em;">CHANGE</u>
|
||||
<br/>
|
||||
<ul>
|
||||
<li>Availability Status - Changed the Waiting for Publication status into two new statuses, to clarify the issue.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</content>
|
||||
<author>
|
||||
<name>bletch</name>
|
||||
<email>bletch1971@hotmail.com</email>
|
||||
</author>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<id>urn:uuid:CDD1853D-66EA-4649-AD24-E491D64C853E</id>
|
||||
<title>1.1.77 (1.1.77.1)</title>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
{
|
||||
Unknown,
|
||||
Unavailable,
|
||||
Waiting,
|
||||
Available
|
||||
LocalOnly,
|
||||
PublicOnly,
|
||||
Available,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using NLog;
|
||||
using ServerManagerTool.Common.Lib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -129,45 +128,6 @@ namespace ServerManagerTool.Common.Utils
|
|||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> CheckServerStatusViaAPI(Uri uri, IPEndPoint endpoint)
|
||||
{
|
||||
try
|
||||
{
|
||||
string jsonString;
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
jsonString = await client.DownloadStringTaskAsync(uri);
|
||||
}
|
||||
|
||||
if (jsonString == null)
|
||||
{
|
||||
_logger.Debug($"Server info request returned null string for {endpoint.Address}:{endpoint.Port}");
|
||||
return false;
|
||||
}
|
||||
|
||||
JObject query = JObject.Parse(jsonString);
|
||||
if (query == null)
|
||||
{
|
||||
_logger.Debug($"Server info request failed to parse for {endpoint.Address}:{endpoint.Port} - '{jsonString}'");
|
||||
return false;
|
||||
}
|
||||
|
||||
var available = query.SelectToken("available");
|
||||
if (available == null)
|
||||
{
|
||||
_logger.Debug($"Server at {endpoint.Address}:{endpoint.Port} returned no availability.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool)available;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug($"{nameof(CheckServerStatusViaAPI)} - Failed checking status via API for: {endpoint.Address}:{endpoint.Port}. {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task PerformCallToAPIAsync(Uri uri)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue