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
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue