Skip to content

Commit

Permalink
add cancellation token for rcon connection to allow more granular con…
Browse files Browse the repository at this point in the history
…trol
  • Loading branch information
RaidMax committed Mar 1, 2022
1 parent c22bfed commit 57558f6
Show file tree
Hide file tree
Showing 17 changed files with 187 additions and 132 deletions.
2 changes: 1 addition & 1 deletion Application/Commands/MapAndGameTypeCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public override async Task ExecuteAsync(GameEvent gameEvent)

_logger.LogDebug("Changing map to {Map} and gametype {Gametype}", map, gametype);

await gameEvent.Owner.SetDvarAsync("g_gametype", gametype);
await gameEvent.Owner.SetDvarAsync("g_gametype", gametype, gameEvent.Owner.Manager.CancellationToken);
gameEvent.Owner.Broadcast(_translationLookup["COMMANDS_MAP_SUCCESS"].FormatExt(map));
await Task.Delay(gameEvent.Owner.Manager.GetApplicationSettings().Configuration().MapChangeDelaySeconds);

Expand Down
43 changes: 22 additions & 21 deletions Application/IW4MServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ protected override async Task<bool> ProcessEvent(GameEvent E)

if (!string.IsNullOrEmpty(CustomSayName))
{
await this.SetDvarAsync("sv_sayname", CustomSayName);
await this.SetDvarAsync("sv_sayname", CustomSayName, Manager.CancellationToken);
}

Throttled = false;
Expand Down Expand Up @@ -783,7 +783,7 @@ private async Task OnClientUpdate(EFClient origin)
async Task<List<EFClient>[]> PollPlayersAsync()
{
var currentClients = GetClientsAsList();
var statusResponse = (await this.GetStatusAsync());
var statusResponse = await this.GetStatusAsync(Manager.CancellationToken);
var polledClients = statusResponse.Clients.AsEnumerable();

if (Manager.GetApplicationSettings().Configuration().IgnoreBots)
Expand Down Expand Up @@ -1109,7 +1109,7 @@ public async Task Initialize()
RemoteConnection = RConConnectionFactory.CreateConnection(ResolvedIpEndPoint, Password, RconParser.RConEngine);
RemoteConnection.SetConfiguration(RconParser);

var version = await this.GetMappedDvarValueOrDefaultAsync<string>("version");
var version = await this.GetMappedDvarValueOrDefaultAsync<string>("version", token: Manager.CancellationToken);
Version = version.Value;
GameName = Utilities.GetGame(version.Value ?? RconParser.Version);

Expand All @@ -1126,7 +1126,7 @@ public async Task Initialize()
Version = RconParser.Version;
}

var svRunning = await this.GetMappedDvarValueOrDefaultAsync<string>("sv_running");
var svRunning = await this.GetMappedDvarValueOrDefaultAsync<string>("sv_running", token: Manager.CancellationToken);

if (!string.IsNullOrEmpty(svRunning.Value) && svRunning.Value != "1")
{
Expand All @@ -1135,27 +1135,28 @@ public async Task Initialize()

var infoResponse = RconParser.Configuration.CommandPrefixes.RConGetInfo != null ? await this.GetInfoAsync() : null;

string hostname = (await this.GetMappedDvarValueOrDefaultAsync<string>("sv_hostname", "hostname", infoResponse)).Value;
string mapname = (await this.GetMappedDvarValueOrDefaultAsync<string>("mapname", infoResponse: infoResponse)).Value;
int maxplayers = (await this.GetMappedDvarValueOrDefaultAsync<int>("sv_maxclients", infoResponse: infoResponse)).Value;
string gametype = (await this.GetMappedDvarValueOrDefaultAsync<string>("g_gametype", "gametype", infoResponse)).Value;
var basepath = await this.GetMappedDvarValueOrDefaultAsync<string>("fs_basepath");
var basegame = await this.GetMappedDvarValueOrDefaultAsync<string>("fs_basegame");
var homepath = await this.GetMappedDvarValueOrDefaultAsync<string>("fs_homepath");
var game = (await this.GetMappedDvarValueOrDefaultAsync<string>("fs_game", infoResponse: infoResponse));
var logfile = await this.GetMappedDvarValueOrDefaultAsync<string>("g_log");
var logsync = await this.GetMappedDvarValueOrDefaultAsync<int>("g_logsync");
var ip = await this.GetMappedDvarValueOrDefaultAsync<string>("net_ip");
var gamePassword = await this.GetMappedDvarValueOrDefaultAsync("g_password", overrideDefault: "");
var hostname = (await this.GetMappedDvarValueOrDefaultAsync<string>("sv_hostname", "hostname", infoResponse, token: Manager.CancellationToken)).Value;
var mapname = (await this.GetMappedDvarValueOrDefaultAsync<string>("mapname", infoResponse: infoResponse, token: Manager.CancellationToken)).Value;
var maxplayers = (await this.GetMappedDvarValueOrDefaultAsync<int>("sv_maxclients", infoResponse: infoResponse, token: Manager.CancellationToken)).Value;
var gametype = (await this.GetMappedDvarValueOrDefaultAsync<string>("g_gametype", "gametype", infoResponse, token: Manager.CancellationToken)).Value;
var basepath = await this.GetMappedDvarValueOrDefaultAsync<string>("fs_basepath", token: Manager.CancellationToken);
var basegame = await this.GetMappedDvarValueOrDefaultAsync<string>("fs_basegame", token: Manager.CancellationToken);
var homepath = await this.GetMappedDvarValueOrDefaultAsync<string>("fs_homepath", token: Manager.CancellationToken);
var game = await this.GetMappedDvarValueOrDefaultAsync<string>("fs_game", infoResponse: infoResponse, token: Manager.CancellationToken);
var logfile = await this.GetMappedDvarValueOrDefaultAsync<string>("g_log", token: Manager.CancellationToken);
var logsync = await this.GetMappedDvarValueOrDefaultAsync<int>("g_logsync", token: Manager.CancellationToken);
var ip = await this.GetMappedDvarValueOrDefaultAsync<string>("net_ip", token: Manager.CancellationToken);
var gamePassword = await this.GetMappedDvarValueOrDefaultAsync("g_password", overrideDefault: "", token: Manager.CancellationToken);

if (Manager.GetApplicationSettings().Configuration().EnableCustomSayName)
{
await this.SetDvarAsync("sv_sayname", Manager.GetApplicationSettings().Configuration().CustomSayName);
await this.SetDvarAsync("sv_sayname", Manager.GetApplicationSettings().Configuration().CustomSayName,
Manager.CancellationToken);
}

try
{
var website = await this.GetMappedDvarValueOrDefaultAsync<string>("_website");
var website = await this.GetMappedDvarValueOrDefaultAsync<string>("_website", token: Manager.CancellationToken);

// this occurs for games that don't give us anything back when
// the dvar is not set
Expand Down Expand Up @@ -1201,14 +1202,14 @@ public async Task Initialize()

if (logsync.Value == 0)
{
await this.SetDvarAsync("g_logsync", 2); // set to 2 for continous in other games, clamps to 1 for IW4
await this.SetDvarAsync("g_logsync", 2, Manager.CancellationToken); // set to 2 for continous in other games, clamps to 1 for IW4
needsRestart = true;
}

if (string.IsNullOrWhiteSpace(logfile.Value))
{
logfile.Value = "games_mp.log";
await this.SetDvarAsync("g_log", logfile.Value);
await this.SetDvarAsync("g_log", logfile.Value, Manager.CancellationToken);
needsRestart = true;
}

Expand All @@ -1220,7 +1221,7 @@ public async Task Initialize()
}

// this DVAR isn't set until the a map is loaded
await this.SetDvarAsync("logfile", 2);
await this.SetDvarAsync("logfile", 2, Manager.CancellationToken);
}

CustomCallback = await ScriptLoaded();
Expand Down
45 changes: 24 additions & 21 deletions Application/RConParsers/BaseRConParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Data.Models;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -77,19 +78,19 @@ public BaseRConParser(ILogger<BaseRConParser> logger, IParserRegexFactory parser
public string RConEngine { get; set; } = "COD";
public bool IsOneLog { get; set; }

public async Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command)
public async Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command, CancellationToken token = default)
{
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command);
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command, token);
return response.Where(item => item != Configuration.CommandPrefixes.RConResponse).ToArray();
}

public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default)
public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default, CancellationToken token = default)
{
string[] lineSplit;

try
{
lineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.GET_DVAR, dvarName);
lineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.GET_DVAR, dvarName, token);
}
catch
{
Expand All @@ -98,18 +99,18 @@ public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dv
throw;
}

lineSplit = new string[0];
lineSplit = Array.Empty<string>();
}

string response = string.Join('\n', lineSplit).TrimEnd('\0');
var response = string.Join('\n', lineSplit).TrimEnd('\0');
var match = Regex.Match(response, Configuration.Dvar.Pattern);

if (response.Contains("Unknown command") ||
!match.Success)
{
if (fallbackValue != null)
{
return new Dvar<T>()
return new Dvar<T>
{
Name = dvarName,
Value = fallbackValue
Expand All @@ -119,17 +120,17 @@ public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dv
throw new DvarException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR"].FormatExt(dvarName));
}

string value = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarValue]].Value;
string defaultValue = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarDefaultValue]].Value;
string latchedValue = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarLatchedValue]].Value;
var value = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarValue]].Value;
var defaultValue = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarDefaultValue]].Value;
var latchedValue = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarLatchedValue]].Value;

string removeTrailingColorCode(string input) => Regex.Replace(input, @"\^7$", "");
string RemoveTrailingColorCode(string input) => Regex.Replace(input, @"\^7$", "");

value = removeTrailingColorCode(value);
defaultValue = removeTrailingColorCode(defaultValue);
latchedValue = removeTrailingColorCode(latchedValue);
value = RemoveTrailingColorCode(value);
defaultValue = RemoveTrailingColorCode(defaultValue);
latchedValue = RemoveTrailingColorCode(latchedValue);

return new Dvar<T>()
return new Dvar<T>
{
Name = dvarName,
Value = string.IsNullOrEmpty(value) ? default : (T)Convert.ChangeType(value, typeof(T)),
Expand All @@ -139,10 +140,12 @@ public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dv
};
}

public virtual async Task<IStatusResponse> GetStatusAsync(IRConConnection connection)
public virtual async Task<IStatusResponse> GetStatusAsync(IRConConnection connection, CancellationToken token = default)
{
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
_logger.LogDebug("Status Response {response}", string.Join(Environment.NewLine, response));
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS, "status", token);

_logger.LogDebug("Status Response {Response}", string.Join(Environment.NewLine, response));

return new StatusResponse
{
Clients = ClientsFromStatus(response).ToArray(),
Expand Down Expand Up @@ -183,13 +186,13 @@ private T GetValueFromStatus<T>(IEnumerable<string> response, ParserRegex.GroupT
return (T)Convert.ChangeType(value, typeof(T));
}

public async Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue)
public async Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue, CancellationToken token = default)
{
string dvarString = (dvarValue is string str)
var dvarString = (dvarValue is string str)
? $"{dvarName} \"{str}\""
: $"{dvarName} {dvarValue}";

return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, dvarString)).Length > 0;
return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, dvarString, token)).Length > 0;
}

private List<EFClient> ClientsFromStatus(string[] Status)
Expand Down
Loading

0 comments on commit 57558f6

Please sign in to comment.