support hostnames for server config

This commit is contained in:
RaidMax 2021-07-11 17:26:30 -05:00
parent 5ef00d6dae
commit e2ea5c6ce0
12 changed files with 59 additions and 52 deletions

View File

@ -1,4 +1,5 @@
using System;
using System.Net;
using SharedLibraryCore.Interfaces;
using System.Text;
using Integrations.Cod;
@ -26,21 +27,15 @@ namespace IW4MAdmin.Application.Factories
_serviceProvider = serviceProvider;
}
/// <summary>
/// creates a new rcon connection instance
/// </summary>
/// <param name="ipAddress">ip address of the server</param>
/// <param name="port">port of the server</param>
/// <param name="password">rcon password of the server</param>
/// <returns></returns>
public IRConConnection CreateConnection(string ipAddress, int port, string password, string rconEngine)
/// <inheritdoc/>
public IRConConnection CreateConnection(IPEndPoint ipEndpoint, string password, string rconEngine)
{
return rconEngine switch
{
"COD" => new CodRConConnection(ipAddress, port, password,
"COD" => new CodRConConnection(ipEndpoint, password,
_serviceProvider.GetRequiredService<ILogger<CodRConConnection>>(), GameEncoding),
"Source" => new SourceRConConnection(_serviceProvider.GetRequiredService<ILogger<SourceRConConnection>>(),
_serviceProvider.GetRequiredService<IRConClientFactory>(), ipAddress, port, password),
_serviceProvider.GetRequiredService<IRConClientFactory>(), ipEndpoint, password),
_ => throw new ArgumentException($"No supported RCon engine available for '{rconEngine}'")
};
}

View File

@ -11,6 +11,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
@ -1059,6 +1060,16 @@ namespace IW4MAdmin
public async Task Initialize()
{
try
{
ResolvedIpEndPoint = new IPEndPoint((await Dns.GetHostAddressesAsync(IP)).First(), Port);
}
catch (Exception ex)
{
ServerLogger.LogWarning(ex, "Could not resolve hostname or IP for RCon connection {IP}:{Port}", IP, Port);
ResolvedIpEndPoint = new IPEndPoint(IPAddress.Parse(IP), Port);
}
RconParser = Manager.AdditionalRConParsers
.FirstOrDefault(_parser => _parser.Version == ServerConfig.RConParserVersion);
@ -1068,7 +1079,7 @@ namespace IW4MAdmin
RconParser ??= Manager.AdditionalRConParsers[0];
EventParser ??= Manager.AdditionalEventParsers[0];
RemoteConnection = RConConnectionFactory.CreateConnection(IP, Port, Password, RconParser.RConEngine);
RemoteConnection = RConConnectionFactory.CreateConnection(ResolvedIpEndPoint, Password, RconParser.RConEngine);
RemoteConnection.SetConfiguration(RconParser);
var version = await this.GetMappedDvarValueOrDefaultAsync<string>("version");

View File

@ -32,12 +32,12 @@ namespace Integrations.Cod
private readonly ILogger _log;
private readonly Encoding _gameEncoding;
public CodRConConnection(string ipAddress, int port, string password, ILogger<CodRConConnection> log, Encoding gameEncoding)
public CodRConConnection(IPEndPoint ipEndpoint, string password, ILogger<CodRConConnection> log, Encoding gameEncoding)
{
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
_gameEncoding = gameEncoding;
RConPassword = password;
_gameEncoding = gameEncoding;
_log = log;
Endpoint = ipEndpoint;
}
public void SetConfiguration(IRConParser parser)

View File

@ -1,9 +1,10 @@
using RconSharp;
using System.Net;
using RconSharp;
namespace Integrations.Source.Interfaces
{
public interface IRConClientFactory
{
RconClient CreateClient(string hostname, int port);
RconClient CreateClient(IPEndPoint ipEndPoint);
}
}

View File

@ -1,13 +1,14 @@
using Integrations.Source.Interfaces;
using System.Net;
using Integrations.Source.Interfaces;
using RconSharp;
namespace Integrations.Source
{
public class RConClientFactory : IRConClientFactory
{
public RconClient CreateClient(string hostname, int port)
public RconClient CreateClient(IPEndPoint ipEndPoint)
{
return RconClient.Create(hostname, port);
return RconClient.Create(ipEndPoint.Address.ToString(), ipEndPoint.Port);
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
@ -20,8 +21,7 @@ namespace Integrations.Source
{
private readonly ILogger _logger;
private readonly string _password;
private readonly string _hostname;
private readonly int _port;
private readonly IPEndPoint _ipEndPoint;
private readonly IRConClientFactory _rconClientFactory;
private readonly SemaphoreSlim _activeQuery;
@ -34,13 +34,12 @@ namespace Integrations.Source
private bool _needNewSocket = true;
public SourceRConConnection(ILogger<SourceRConConnection> logger, IRConClientFactory rconClientFactory,
string hostname, int port, string password)
IPEndPoint ipEndPoint, string password)
{
_rconClientFactory = rconClientFactory;
_password = password;
_hostname = hostname;
_port = port;
_logger = logger;
_ipEndPoint = ipEndPoint;
_activeQuery = new SemaphoreSlim(1, 1);
}
@ -67,12 +66,12 @@ namespace Integrations.Source
// ignored
}
_rconClient = _rconClientFactory.CreateClient(_hostname, _port);
_rconClient = _rconClientFactory.CreateClient(_ipEndPoint);
_authenticated = false;
_needNewSocket = false;
}
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
using (LogContext.PushProperty("Server", _ipEndPoint.ToString()))
{
_logger.LogDebug("Connecting to RCon socket");
}
@ -90,7 +89,7 @@ namespace Integrations.Source
parameters = parameters.ReplaceUnfriendlyCharacters();
parameters = parameters.StripColors();
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
using (LogContext.PushProperty("Server", _ipEndPoint.ToString()))
{
_logger.LogDebug("Sending query {Type} with parameters \"{Parameters}\"", type, parameters);
}
@ -98,7 +97,7 @@ namespace Integrations.Source
var response = await _rconClient.ExecuteCommandAsync(parameters, multiPacket)
.WithTimeout(ConnectionTimeout);
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
using (LogContext.PushProperty("Server", $"{_ipEndPoint}"))
{
_logger.LogDebug("Received RCon response {Response}", response);
}
@ -115,7 +114,7 @@ namespace Integrations.Source
catch (SocketException ex)
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
using (LogContext.PushProperty("Server", _ipEndPoint.ToString()))
{
_logger.LogError(ex, "Socket exception encountered while attempting to communicate with server");
}
@ -128,7 +127,7 @@ namespace Integrations.Source
catch (Exception ex) when (ex.GetType() != typeof(NetworkException) &&
ex.GetType() != typeof(ServerException))
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
using (LogContext.PushProperty("Server", _ipEndPoint.ToString()))
{
_logger.LogError(ex, "Could not execute RCon query {Parameters}", parameters);
}
@ -160,7 +159,7 @@ namespace Integrations.Source
{
if (!_authenticated)
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
using (LogContext.PushProperty("Server", _ipEndPoint.ToString()))
{
_logger.LogDebug("Authenticating to RCon socket");
}
@ -170,7 +169,7 @@ namespace Integrations.Source
if (!_authenticated)
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
using (LogContext.PushProperty("Server", _ipEndPoint.ToString()))
{
_logger.LogError("Could not login to server");
}

View File

@ -87,13 +87,9 @@ namespace SharedLibraryCore.Configuration
while (string.IsNullOrEmpty(IPAddress))
{
string input = Utilities.PromptString(loc["SETUP_SERVER_IP"]);
if (System.Net.IPAddress.TryParse(input, out System.Net.IPAddress ip))
{
var input = Utilities.PromptString(loc["SETUP_SERVER_IP"]);
IPAddress = input;
}
}
Port = Utilities.PromptInt(loc["SETUP_SERVER_PORT"], null, 1, ushort.MaxValue);
Password = Utilities.PromptString(loc["SETUP_SERVER_RCON"]);

View File

@ -10,10 +10,6 @@ namespace SharedLibraryCore.Configuration.Validation
{
public ServerConfigurationValidator()
{
RuleFor(_server => _server.IPAddress)
.NotEmpty()
.Must(_address => IPAddress.TryParse(_address, out _));
RuleFor(_server => _server.Port)
.InclusiveBetween(1, ushort.MaxValue);

View File

@ -1,4 +1,6 @@
namespace SharedLibraryCore.Interfaces
using System.Net;
namespace SharedLibraryCore.Interfaces
{
/// <summary>
/// defines the capabilities of an RCon connection factory
@ -8,11 +10,10 @@
/// <summary>
/// creates an rcon connection instance
/// </summary>
/// <param name="ipAddress">ip address of the server</param>
/// <param name="port">port of the server</param>
/// <param name="ipEndpoint">ip address and port of the server</param>
/// <param name="password"> password of the server</param>
/// <param name="rconEngine">engine to create the rcon connection to</param>
/// <returns>instance of rcon connection</returns>
IRConConnection CreateConnection(string ipAddress, int port, string password, string rconEngine);
IRConConnection CreateConnection(IPEndPoint ipEndpoint, string password, string rconEngine);
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@ -58,7 +59,9 @@ namespace SharedLibraryCore
InitializeAutoMessages();
}
public long EndPoint => Convert.ToInt64($"{IP.Replace(".", "")}{Port}");
public long EndPoint => IPAddress.TryParse(IP, out _)
? Convert.ToInt64($"{IP.Replace(".", "")}{Port}")
: $"{IP.Replace(".", "")}{Port}".GetStableHashCode();
/// <summary>
/// Returns list of all current players
@ -303,7 +306,7 @@ namespace SharedLibraryCore
{
get
{
return Clients.Where(p => p != null/* && !p.IsBot*/).Count();
return Clients.Count(p => p != null && !p.IsBot);
}
}
public int MaxClients { get; protected set; }
@ -320,7 +323,11 @@ namespace SharedLibraryCore
public SemaphoreSlim EventProcessing { get; private set; }
// Internal
/// <summary>
/// this is actually the hostname now
/// </summary>
public string IP { get; protected set; }
public IPEndPoint ResolvedIpEndPoint { get; protected set; }
public string Version { get; protected set; }
public bool IsInitialized { get; set; }
protected readonly ILogger ServerLogger;

View File

@ -12,7 +12,7 @@ namespace WebfrontCore.ViewComponents
{
public IViewComponentResult Invoke(Game? game)
{
var servers = Program.Manager.GetServers().Where(_server => !game.HasValue ? true : _server.GameName == game);
var servers = Program.Manager.GetServers().Where(_server => !game.HasValue || _server.GameName == game);
var serverInfo = servers.Select(s => new ServerInfo()
{
@ -36,8 +36,8 @@ namespace WebfrontCore.ViewComponents
}).ToList(),
ChatHistory = s.ChatHistory.ToList(),
Online = !s.Throttled,
IPAddress = $"{(IPAddress.Parse(s.IP).IsInternal() ? Program.Manager.ExternalIPAddress : s.IP)}:{s.Port}",
ConnectProtocolUrl = s.EventParser.URLProtocolFormat.FormatExt(IPAddress.Parse(s.IP).IsInternal() ? Program.Manager.ExternalIPAddress : s.IP, s.Port)
IPAddress = $"{(s.ResolvedIpEndPoint.Address.IsInternal() ? Program.Manager.ExternalIPAddress : s.IP)}:{s.Port}",
ConnectProtocolUrl = s.EventParser.URLProtocolFormat.FormatExt(s.ResolvedIpEndPoint.Address.IsInternal() ? Program.Manager.ExternalIPAddress : s.IP, s.Port)
}).ToList();
return View("_List", serverInfo);
}

View File

@ -139,7 +139,7 @@
: null;
var headShots = allPerServer.Any()
? allPerServer.Where(hit => hit.MeansOfDeath?.Name == headshotKey || hit.MeansOfDeath?.Name == headshotKey2).Sum(hit => hit.HitCount)
? allPerServer.Where(hit => hit.MeansOfDeath?.Name == headshotKey || hit.HitLocation?.Name == headshotKey2).Sum(hit => hit.HitCount)
: (int?) null; // want to default to -- in ui instead of 0
var meleeKills = allPerServer.Any()