1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-10 15:20:48 -05:00

improve CS:GO compatibility

This commit is contained in:
RaidMax
2021-06-11 11:52:30 -05:00
parent d309565350
commit d314d7ba2c
8 changed files with 183 additions and 57 deletions

View File

@ -0,0 +1,48 @@
using System.Text;
namespace Integrations.Source.Extensions
{
public static class SourceExtensions
{
public static string ReplaceUnfriendlyCharacters(this string source)
{
var result = new StringBuilder();
var quoteStart = false;
var quoteIndex = 0;
var index = 0;
foreach (var character in source)
{
if (character == '%')
{
result.Append('‰');
}
else if ((character == '"' || character == '\'') && index + 1 != source.Length)
{
if (quoteIndex > 0)
{
result.Append(!quoteStart ? "«" : "»");
quoteStart = !quoteStart;
}
else
{
result.Append('"');
}
quoteIndex++;
}
else
{
result.Append(character);
}
index++;
}
return result.ToString();
}
}
}

View File

@ -4,6 +4,12 @@
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyName>Integrations.Source</AssemblyName>
<RootNamespace>Integrations.Source</RootNamespace>
<Configurations>Debug;Release;Prerelease</Configurations>
<Platforms>AnyCPU</Platforms>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Prerelease' ">
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>

View File

@ -1,6 +1,9 @@
using System.Linq;
using System;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Integrations.Source.Extensions;
using Integrations.Source.Interfaces;
using Microsoft.Extensions.Logging;
using RconSharp;
@ -20,82 +23,145 @@ namespace Integrations.Source
private readonly string _hostname;
private readonly int _port;
private readonly IRConClientFactory _rconClientFactory;
private readonly SemaphoreSlim _activeQuery;
private static readonly TimeSpan FloodDelay = TimeSpan.FromMilliseconds(250);
private DateTime _lastQuery = DateTime.Now;
private RconClient _rconClient;
public SourceRConConnection(ILogger<SourceRConConnection> logger, IRConClientFactory rconClientFactory,
string hostname, int port, string password)
{
_rconClient = rconClientFactory.CreateClient(hostname, port);
_rconClientFactory = rconClientFactory;
_password = password;
_hostname = hostname;
_port = port;
_logger = logger;
_rconClient = _rconClientFactory.CreateClient(_hostname, _port);
_activeQuery = new SemaphoreSlim(1, 1);
}
~SourceRConConnection()
{
_activeQuery.Dispose();
}
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
{
await _rconClient.ConnectAsync();
bool authenticated;
try
{
authenticated = await _rconClient.AuthenticateAsync(_password);
}
catch (SocketException ex)
{
// occurs when the server comes back from hibernation
// this is probably a bug in the library
if (ex.ErrorCode == 10053 || ex.ErrorCode == 10054)
await _activeQuery.WaitAsync();
var diff = DateTime.Now - _lastQuery;
if (diff < FloodDelay)
{
await Task.Delay(FloodDelay - diff);
}
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogDebug("Connecting to RCon socket");
}
await _rconClient.ConnectAsync();
bool authenticated;
try
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogWarning(ex,
"Server appears to resumed from hibernation, so we are using a new socket");
_logger.LogDebug("Authenticating to RCon socket");
}
_rconClient = _rconClientFactory.CreateClient(_hostname, _port);
authenticated = await _rconClient.AuthenticateAsync(_password);
}
catch (SocketException ex)
{
// occurs when the server comes back from hibernation
// this is probably a bug in the library
if (ex.ErrorCode == 10053 || ex.ErrorCode == 10054)
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogWarning(ex,
"Server appears to resumed from hibernation, so we are using a new socket");
}
try
{
_rconClient.Disconnect();
}
catch
{
// ignored
}
_rconClient = _rconClientFactory.CreateClient(_hostname, _port);
}
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogError(ex, "Error occurred authenticating with server");
}
throw new NetworkException("Error occurred authenticating with server");
}
if (!authenticated)
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogError("Could not login to server");
}
throw new ServerException("Could not authenticate to server with provided password");
}
if (type == StaticHelpers.QueryType.COMMAND_STATUS)
{
parameters = "status";
}
parameters = parameters.ReplaceUnfriendlyCharacters();
parameters = parameters.StripColors();
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogError("Could not login to server");
_logger.LogDebug("Sending query {Type} with parameters \"{Parameters}\"", type, parameters);
}
throw new NetworkException("Could not authenticate with server");
var response = await _rconClient.ExecuteCommandAsync(parameters, true);
using (LogContext.PushProperty("Server", $"{_rconClient.Host}:{_rconClient.Port}"))
{
_logger.LogDebug("Received RCon response {Response}", response);
}
var split = response.TrimEnd('\n').Split('\n');
return split.Take(split.Length - 1).ToArray();
}
if (!authenticated)
catch (Exception ex) when (ex.GetType() != typeof(NetworkException) &&
ex.GetType() != typeof(ServerException))
{
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogError("Could not login to server");
_logger.LogError(ex, "Could not execute RCon query {Parameters}", parameters);
}
throw new ServerException("Could not authenticate to server with provided password");
throw new NetworkException("Unable to communicate with server");
}
if (type == StaticHelpers.QueryType.COMMAND_STATUS)
finally
{
parameters = "status";
if (_activeQuery.CurrentCount == 0)
{
_activeQuery.Release();
}
_lastQuery = DateTime.Now;
}
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
{
_logger.LogDebug("Sending query {Type} with parameters {Parameters}", type, parameters);
}
var response = await _rconClient.ExecuteCommandAsync(parameters.StripColors(), true);
using (LogContext.PushProperty("Server", $"{_rconClient.Host}:{_rconClient.Port}"))
{
_logger.LogDebug("Received RCon response {Response}", response);
}
var split = response.TrimEnd('\n').Split('\n');
return split.Take(split.Length - 1).ToArray();
}
public void SetConfiguration(IRConParser config)