update CoD4x parser

tweak handling segmented status response
actually support more than 18 clients LOL
This commit is contained in:
RaidMax 2020-12-02 14:29:49 -06:00
parent bd3f0caf60
commit 6648b75255
6 changed files with 44 additions and 36 deletions

View File

@ -5,12 +5,13 @@ using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using SharedLibraryCore;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database;
using SharedLibraryCore.Database.MigrationContext;
using ILogger = Serilog.ILogger;
namespace IW4MAdmin.Application.Extensions
{
@ -45,6 +46,8 @@ namespace IW4MAdmin.Application.Extensions
}
services.AddLogging(builder => builder.AddSerilog(_defaultLogger, dispose: true));
services.AddSingleton(new LoggerFactory()
.AddSerilog(_defaultLogger, true));
return services;
}
@ -76,18 +79,19 @@ namespace IW4MAdmin.Application.Extensions
case "mysql":
var appendTimeout = !appConfig.ConnectionString.Contains("default command timeout",
StringComparison.InvariantCultureIgnoreCase);
var mysqlBuilder = new DbContextOptionsBuilder<MySqlDatabaseContext>()
services.AddSingleton(sp => (DbContextOptions) new DbContextOptionsBuilder<MySqlDatabaseContext>()
.UseMySql(appConfig.ConnectionString + (appendTimeout ? ";default command timeout=0" : ""),
mysqlOptions => mysqlOptions.EnableRetryOnFailure());
services.AddSingleton((DbContextOptions) mysqlBuilder.Options);
mysqlOptions => mysqlOptions.EnableRetryOnFailure())
.UseLoggerFactory(sp.GetRequiredService<ILoggerFactory>()).Options);
return services;
case "postgresql":
appendTimeout = !appConfig.ConnectionString.Contains("Command Timeout",
StringComparison.InvariantCultureIgnoreCase);
var postgresqlBuilder = new DbContextOptionsBuilder<PostgresqlDatabaseContext>()
.UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""),
postgresqlOptions => postgresqlOptions.EnableRetryOnFailure());
services.AddSingleton((DbContextOptions) postgresqlBuilder.Options);
services.AddSingleton(sp =>
(DbContextOptions) new DbContextOptionsBuilder<PostgresqlDatabaseContext>()
.UseNpgsql(appConfig.ConnectionString + (appendTimeout ? ";Command Timeout=0" : ""),
postgresqlOptions => postgresqlOptions.EnableRetryOnFailure())
.UseLoggerFactory(sp.GetRequiredService<ILoggerFactory>()).Options);
return services;
default:
throw new ArgumentException($"No context available for {appConfig.DatabaseProvider}");

View File

@ -18,7 +18,7 @@ namespace IW4MAdmin.Application.RCon
}
public int ConnectionAttempts { get; set; }
const int BufferSize = 4096;
const int BufferSize = 8192;
public readonly byte[] ReceiveBuffer = new byte[BufferSize];
public readonly SemaphoreSlim OnComplete = new SemaphoreSlim(1, 1);
public readonly ManualResetEventSlim OnSentData = new ManualResetEventSlim(false);

View File

@ -407,37 +407,39 @@ namespace IW4MAdmin.Application.RCon
return;
}
if (sender is Socket sock)
if (!(sender is Socket sock))
{
var state = ActiveQueries[this.Endpoint];
state.BytesReadPerSegment.Add(e.BytesTransferred);
return;
}
var state = ActiveQueries[this.Endpoint];
state.BytesReadPerSegment.Add(e.BytesTransferred);
try
try
{
var totalBytesTransferred = e.BytesTransferred;
// we still have available data so the payload was segmented
while (sock.Available > 0)
{
// we still have available data so the payload was segmented
if (sock.Available > 0)
state.ReceiveEventArgs.SetBuffer(state.ReceiveBuffer, totalBytesTransferred, sock.Available);
if (sock.ReceiveAsync(state.ReceiveEventArgs))
{
state.ReceiveEventArgs.SetBuffer(state.ReceiveBuffer, e.BytesTransferred, state.ReceiveBuffer.Length - e.BytesTransferred);
if (!sock.ReceiveAsync(state.ReceiveEventArgs))
{
_log.LogDebug("Read {bytesTransferred} synchronous bytes from {endpoint}", state.ReceiveEventArgs.BytesTransferred, e.RemoteEndPoint);
// we need to increment this here because the callback isn't executed if there's no pending IO
state.BytesReadPerSegment.Add(state.ReceiveEventArgs.BytesTransferred);
ActiveQueries[this.Endpoint].OnReceivedData.Set();
}
}
else
{
ActiveQueries[this.Endpoint].OnReceivedData.Set();
continue;
}
_log.LogDebug("Read {bytesTransferred} synchronous bytes from {endpoint}", state.ReceiveEventArgs.BytesTransferred, e.RemoteEndPoint);
// we need to increment this here because the callback isn't executed if there's no pending IO
state.BytesReadPerSegment.Add(state.ReceiveEventArgs.BytesTransferred);
totalBytesTransferred += state.ReceiveEventArgs.BytesTransferred;
}
ActiveQueries[this.Endpoint].OnReceivedData.Set();
}
catch (ObjectDisposedException)
{
ActiveQueries[this.Endpoint].OnReceivedData.Set();
}
catch (ObjectDisposedException)
{
ActiveQueries[this.Endpoint].OnReceivedData.Set();
}
}

View File

@ -205,7 +205,8 @@ namespace IW4MAdmin.Application.RconParsers
if (match.Success)
{
if (match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]] == "ZMBI")
if (match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]] == "ZMBI" ||
match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]] == "CNCT")
{
_logger.LogDebug("Ignoring detected client {client} because they are zombie state", string.Join(",", match.Values));
continue;

View File

@ -15,9 +15,10 @@ var plugin = {
eventParser = manager.GenerateDynamicEventParser(this.name);
rconParser.Configuration.StatusHeader.Pattern = 'num +score +ping +playerid +steamid +name +lastmsg +address +qport +rate *';
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]{16,32})|bot[0-9]+) ([0-9]+) +(.{0,32}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$';
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]{16,32})|0) +([[0-9]+|0]) +(.{0,32}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|bot) +(-*[0-9]+) +([0-9]+) *$';
rconParser.Configuration.Status.AddMapping(104, 6); // RConName
rconParser.Configuration.Status.AddMapping(105, 8); // RConIPAddress
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
rconParser.Configuration.Dvar.Pattern = '^"(.+)" is: "(.+)?" default: "(.+)?" info: "(.+)?"$';
rconParser.Configuration.Dvar.AddMapping(109, 2); // DVAR latched value

View File

@ -42,7 +42,7 @@ namespace SharedLibraryCore
ServerConfig = config;
RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password);
EventProcessing = new SemaphoreSlim(1, 1);
Clients = new List<EFClient>(new EFClient[18]);
Clients = new List<EFClient>(new EFClient[64]);
Reports = new List<Report>();
ClientHistory = new Queue<PlayerHistory>();
ChatHistory = new List<ChatInfo>();