fix for runaway regular expression on linux
explicitly set string dvars in quotes to allow setting empty dvars allow piping in input from command line (#114) update the distribution for top stats elo prevent game log file rotation from stopping event parsing
This commit is contained in:
parent
02a784ad09
commit
9fdf4bad9c
1
.gitignore
vendored
1
.gitignore
vendored
@ -241,3 +241,4 @@ launchSettings.json
|
|||||||
/WebfrontCore/wwwroot/fonts
|
/WebfrontCore/wwwroot/fonts
|
||||||
/WebfrontCore/wwwroot/font
|
/WebfrontCore/wwwroot/font
|
||||||
/Plugins/Tests/TestSourceFiles
|
/Plugins/Tests/TestSourceFiles
|
||||||
|
/Tests/ApplicationTests/Files/GameEvents.json
|
||||||
|
@ -25,11 +25,11 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Jint" Version="3.0.0-beta-1632" />
|
<PackageReference Include="Jint" Version="3.0.0-beta-1632" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.1">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.3">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.3" />
|
||||||
<PackageReference Include="RestEase" Version="1.4.10" />
|
<PackageReference Include="RestEase" Version="1.4.10" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -59,11 +59,12 @@ namespace IW4MAdmin.Application
|
|||||||
private readonly ITranslationLookup _translationLookup;
|
private readonly ITranslationLookup _translationLookup;
|
||||||
private readonly IConfigurationHandler<CommandConfiguration> _commandConfiguration;
|
private readonly IConfigurationHandler<CommandConfiguration> _commandConfiguration;
|
||||||
private readonly IGameServerInstanceFactory _serverInstanceFactory;
|
private readonly IGameServerInstanceFactory _serverInstanceFactory;
|
||||||
|
private readonly IParserRegexFactory _parserRegexFactory;
|
||||||
|
|
||||||
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
||||||
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
||||||
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
||||||
IEnumerable<IPlugin> plugins)
|
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory)
|
||||||
{
|
{
|
||||||
MiddlewareActionHandler = actionHandler;
|
MiddlewareActionHandler = actionHandler;
|
||||||
_servers = new ConcurrentBag<Server>();
|
_servers = new ConcurrentBag<Server>();
|
||||||
@ -74,8 +75,8 @@ namespace IW4MAdmin.Application
|
|||||||
ConfigHandler = appConfigHandler;
|
ConfigHandler = appConfigHandler;
|
||||||
StartTime = DateTime.UtcNow;
|
StartTime = DateTime.UtcNow;
|
||||||
PageList = new PageList();
|
PageList = new PageList();
|
||||||
AdditionalEventParsers = new List<IEventParser>() { new BaseEventParser() };
|
AdditionalEventParsers = new List<IEventParser>() { new BaseEventParser(parserRegexFactory) };
|
||||||
AdditionalRConParsers = new List<IRConParser>() { new BaseRConParser() };
|
AdditionalRConParsers = new List<IRConParser>() { new BaseRConParser(parserRegexFactory) };
|
||||||
TokenAuthenticator = new TokenAuthentication();
|
TokenAuthenticator = new TokenAuthentication();
|
||||||
_metaService = new MetaService();
|
_metaService = new MetaService();
|
||||||
_tokenSource = new CancellationTokenSource();
|
_tokenSource = new CancellationTokenSource();
|
||||||
@ -84,6 +85,7 @@ namespace IW4MAdmin.Application
|
|||||||
_translationLookup = translationLookup;
|
_translationLookup = translationLookup;
|
||||||
_commandConfiguration = commandConfiguration;
|
_commandConfiguration = commandConfiguration;
|
||||||
_serverInstanceFactory = serverInstanceFactory;
|
_serverInstanceFactory = serverInstanceFactory;
|
||||||
|
_parserRegexFactory = parserRegexFactory;
|
||||||
Plugins = plugins;
|
Plugins = plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,7 +773,7 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public IRConParser GenerateDynamicRConParser(string name)
|
public IRConParser GenerateDynamicRConParser(string name)
|
||||||
{
|
{
|
||||||
return new DynamicRConParser()
|
return new DynamicRConParser(_parserRegexFactory)
|
||||||
{
|
{
|
||||||
Name = name
|
Name = name
|
||||||
};
|
};
|
||||||
@ -779,7 +781,7 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public IEventParser GenerateDynamicEventParser(string name)
|
public IEventParser GenerateDynamicEventParser(string name)
|
||||||
{
|
{
|
||||||
return new DynamicEventParser()
|
return new DynamicEventParser(_parserRegexFactory)
|
||||||
{
|
{
|
||||||
Name = name
|
Name = name
|
||||||
};
|
};
|
||||||
|
@ -2,18 +2,16 @@
|
|||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.EventParsers
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
{
|
{
|
||||||
public class BaseEventParser : IEventParser
|
public class BaseEventParser : IEventParser
|
||||||
{
|
{
|
||||||
public BaseEventParser()
|
public BaseEventParser(IParserRegexFactory parserRegexFactory)
|
||||||
{
|
{
|
||||||
Configuration = new DynamicEventParserConfiguration()
|
Configuration = new DynamicEventParserConfiguration(parserRegexFactory)
|
||||||
{
|
{
|
||||||
GameDirectory = "main",
|
GameDirectory = "main",
|
||||||
};
|
};
|
||||||
@ -66,6 +64,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.Damage, 11);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.Damage, 11);
|
||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
||||||
|
|
||||||
|
Configuration.Time.Pattern = @"^ *(([0-9]+):([0-9]+) |^[0-9]+ )";
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEventParserConfiguration Configuration { get; set; }
|
public IEventParserConfiguration Configuration { get; set; }
|
||||||
@ -80,16 +80,19 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
public virtual GameEvent GenerateGameEvent(string logLine)
|
public virtual GameEvent GenerateGameEvent(string logLine)
|
||||||
{
|
{
|
||||||
var timeMatch = Regex.Match(logLine, @"^ *(([0-9]+):([0-9]+) |^[0-9]+ )");
|
var timeMatch = Configuration.Time.PatternMatcher.Match(logLine);
|
||||||
int gameTime = 0;
|
int gameTime = 0;
|
||||||
|
|
||||||
if (timeMatch.Success)
|
if (timeMatch.Success)
|
||||||
{
|
{
|
||||||
gameTime = (timeMatch.Groups.Values as IEnumerable<object>)
|
gameTime = timeMatch
|
||||||
|
.Values
|
||||||
.Skip(2)
|
.Skip(2)
|
||||||
.Select(_value => int.Parse(_value.ToString()))
|
// this converts the timestamp into seconds passed
|
||||||
|
.Select((_value, index) => int.Parse(_value.ToString()) * (index == 0 ? 60 : 1))
|
||||||
.Sum();
|
.Sum();
|
||||||
logLine = logLine.Substring(timeMatch.Value.Length);
|
// we want to strip the time from the log line
|
||||||
|
logLine = logLine.Substring(timeMatch.Values.First().Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] lineSplit = logLine.Split(';');
|
string[] lineSplit = logLine.Split(';');
|
||||||
@ -97,27 +100,28 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "say" || eventType == "sayteam")
|
if (eventType == "say" || eventType == "sayteam")
|
||||||
{
|
{
|
||||||
var matchResult = Regex.Match(logLine, Configuration.Say.Pattern);
|
var matchResult = Configuration.Say.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (matchResult.Success)
|
if (matchResult.Success)
|
||||||
{
|
{
|
||||||
string message = matchResult
|
string message = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.Message]]
|
||||||
.Groups[Configuration.Say.GroupMapping[ParserRegex.GroupType.Message]]
|
|
||||||
.ToString()
|
.ToString()
|
||||||
.Replace("\x15", "")
|
.Replace("\x15", "")
|
||||||
.Trim();
|
.Trim();
|
||||||
|
|
||||||
if (message.Length > 0)
|
if (message.Length > 0)
|
||||||
{
|
{
|
||||||
long originId = matchResult.Groups[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle);
|
long originId = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
|
int clientNumber = int.Parse(matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
|
|
||||||
|
// todo: these need to defined outside of here
|
||||||
if (message[0] == '!' || message[0] == '@')
|
if (message[0] == '!' || message[0] == '@')
|
||||||
{
|
{
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Command,
|
Type = GameEvent.EventType.Command,
|
||||||
Data = message,
|
Data = message,
|
||||||
Origin = new EFClient() { NetworkId = originId },
|
Origin = new EFClient() { NetworkId = originId, ClientNumber = clientNumber },
|
||||||
Message = message,
|
Message = message,
|
||||||
Extra = logLine,
|
Extra = logLine,
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
||||||
@ -129,7 +133,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Say,
|
Type = GameEvent.EventType.Say,
|
||||||
Data = message,
|
Data = message,
|
||||||
Origin = new EFClient() { NetworkId = originId },
|
Origin = new EFClient() { NetworkId = originId, ClientNumber = clientNumber },
|
||||||
Message = message,
|
Message = message,
|
||||||
Extra = logLine,
|
Extra = logLine,
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
||||||
@ -141,19 +145,21 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "K")
|
if (eventType == "K")
|
||||||
{
|
{
|
||||||
var match = Regex.Match(logLine, Configuration.Kill.Pattern);
|
var match = Configuration.Kill.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
long originId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].Value.ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
long originId = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
||||||
long targetId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].Value.ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
long targetId = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
||||||
|
int originClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
|
int targetClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Kill,
|
Type = GameEvent.EventType.Kill,
|
||||||
Data = logLine,
|
Data = logLine,
|
||||||
Origin = new EFClient() { NetworkId = originId },
|
Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber },
|
||||||
Target = new EFClient() { NetworkId = targetId },
|
Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber },
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
||||||
GameTime = gameTime
|
GameTime = gameTime
|
||||||
};
|
};
|
||||||
@ -162,19 +168,21 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "D")
|
if (eventType == "D")
|
||||||
{
|
{
|
||||||
var regexMatch = Regex.Match(logLine, Configuration.Damage.Pattern);
|
var match = Configuration.Damage.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (regexMatch.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
long originId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
long originId = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
||||||
long targetId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
long targetId = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
||||||
|
int originClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
|
int targetClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Damage,
|
Type = GameEvent.EventType.Damage,
|
||||||
Data = logLine,
|
Data = logLine,
|
||||||
Origin = new EFClient() { NetworkId = originId },
|
Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber },
|
||||||
Target = new EFClient() { NetworkId = targetId },
|
Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber },
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
||||||
GameTime = gameTime
|
GameTime = gameTime
|
||||||
};
|
};
|
||||||
@ -183,9 +191,9 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "J")
|
if (eventType == "J")
|
||||||
{
|
{
|
||||||
var regexMatch = Regex.Match(logLine, Configuration.Join.Pattern);
|
var match = Configuration.Join.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (regexMatch.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -195,10 +203,10 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
CurrentAlias = new EFAlias()
|
CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
Name = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine(),
|
Name = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine(),
|
||||||
},
|
},
|
||||||
NetworkId = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle),
|
NetworkId = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle),
|
||||||
ClientNumber = Convert.ToInt32(regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
||||||
State = EFClient.ClientState.Connecting,
|
State = EFClient.ClientState.Connecting,
|
||||||
},
|
},
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
@ -210,8 +218,9 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "Q")
|
if (eventType == "Q")
|
||||||
{
|
{
|
||||||
var regexMatch = Regex.Match(logLine, Configuration.Quit.Pattern);
|
var match = Configuration.Quit.PatternMatcher.Match(logLine);
|
||||||
if (regexMatch.Success)
|
|
||||||
|
if (match.Success)
|
||||||
{
|
{
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -221,10 +230,10 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
CurrentAlias = new EFAlias()
|
CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
Name = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine()
|
Name = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine()
|
||||||
},
|
},
|
||||||
NetworkId = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle),
|
NetworkId = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle),
|
||||||
ClientNumber = Convert.ToInt32(regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
ClientNumber = Convert.ToInt32(match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
||||||
State = EFClient.ClientState.Disconnecting
|
State = EFClient.ClientState.Disconnecting
|
||||||
},
|
},
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
@ -279,7 +288,6 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
// this is a custom event printed out by _customcallbacks.gsc (used for anticheat)
|
// this is a custom event printed out by _customcallbacks.gsc (used for anticheat)
|
||||||
if (eventType == "ScriptKill")
|
if (eventType == "ScriptKill")
|
||||||
{
|
{
|
||||||
|
|
||||||
long originId = lineSplit[1].ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
long originId = lineSplit[1].ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
||||||
long targetId = lineSplit[2].ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
long targetId = lineSplit[2].ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
||||||
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using static SharedLibraryCore.Server;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.EventParsers
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
{
|
{
|
||||||
@ -11,5 +8,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
sealed internal class DynamicEventParser : BaseEventParser
|
sealed internal class DynamicEventParser : BaseEventParser
|
||||||
{
|
{
|
||||||
|
public DynamicEventParser(IParserRegexFactory parserRegexFactory) : base(parserRegexFactory)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,24 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
sealed internal class DynamicEventParserConfiguration : IEventParserConfiguration
|
sealed internal class DynamicEventParserConfiguration : IEventParserConfiguration
|
||||||
{
|
{
|
||||||
public string GameDirectory { get; set; }
|
public string GameDirectory { get; set; }
|
||||||
public ParserRegex Say { get; set; } = new ParserRegex();
|
public ParserRegex Say { get; set; }
|
||||||
public ParserRegex Join { get; set; } = new ParserRegex();
|
public ParserRegex Join { get; set; }
|
||||||
public ParserRegex Quit { get; set; } = new ParserRegex();
|
public ParserRegex Quit { get; set; }
|
||||||
public ParserRegex Kill { get; set; } = new ParserRegex();
|
public ParserRegex Kill { get; set; }
|
||||||
public ParserRegex Damage { get; set; } = new ParserRegex();
|
public ParserRegex Damage { get; set; }
|
||||||
public ParserRegex Action { get; set; } = new ParserRegex();
|
public ParserRegex Action { get; set; }
|
||||||
|
public ParserRegex Time { get; set; }
|
||||||
public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber;
|
public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber;
|
||||||
|
|
||||||
|
public DynamicEventParserConfiguration(IParserRegexFactory parserRegexFactory)
|
||||||
|
{
|
||||||
|
Say = parserRegexFactory.CreateParserRegex();
|
||||||
|
Join = parserRegexFactory.CreateParserRegex();
|
||||||
|
Quit = parserRegexFactory.CreateParserRegex();
|
||||||
|
Kill = parserRegexFactory.CreateParserRegex();
|
||||||
|
Damage = parserRegexFactory.CreateParserRegex();
|
||||||
|
Action = parserRegexFactory.CreateParserRegex();
|
||||||
|
Time = parserRegexFactory.CreateParserRegex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
Application/EventParsers/ParserPatternMatcher.cs
Normal file
35
Application/EventParsers/ParserPatternMatcher.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using IW4MAdmin.Application.Misc;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// implementation of the IParserPatternMatcher for windows (really it's the only implementation)
|
||||||
|
/// </summary>
|
||||||
|
public class ParserPatternMatcher : IParserPatternMatcher
|
||||||
|
{
|
||||||
|
private Regex regex;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Compile(string pattern)
|
||||||
|
{
|
||||||
|
regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IMatchResult Match(string input)
|
||||||
|
{
|
||||||
|
var match = regex.Match(input);
|
||||||
|
|
||||||
|
return new ParserMatchResult()
|
||||||
|
{
|
||||||
|
Success = match.Success,
|
||||||
|
Values = (match.Groups as IEnumerable<object>)?
|
||||||
|
.Select(_item => _item.ToString()).ToArray() ?? new string[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
Application/Factories/ParserRegexFactory.cs
Normal file
26
Application/Factories/ParserRegexFactory.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Factories
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of the IParserRegexFactory
|
||||||
|
/// </summary>
|
||||||
|
public class ParserRegexFactory : IParserRegexFactory
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ParserRegexFactory(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ParserRegex CreateParserRegex()
|
||||||
|
{
|
||||||
|
return new ParserRegex(_serviceProvider.GetService<IParserPatternMatcher>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,12 +6,11 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace IW4MAdmin.Application.IO
|
namespace IW4MAdmin.Application.IO
|
||||||
{
|
{
|
||||||
class GameLogEventDetection
|
public class GameLogEventDetection
|
||||||
{
|
{
|
||||||
private long previousFileSize;
|
private long previousFileSize;
|
||||||
private readonly Server _server;
|
private readonly Server _server;
|
||||||
private readonly IGameLogReader _reader;
|
private readonly IGameLogReader _reader;
|
||||||
private readonly string _gameLogFile;
|
|
||||||
private readonly bool _ignoreBots;
|
private readonly bool _ignoreBots;
|
||||||
|
|
||||||
class EventState
|
class EventState
|
||||||
@ -20,12 +19,13 @@ namespace IW4MAdmin.Application.IO
|
|||||||
public string ServerId { get; set; }
|
public string ServerId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameLogEventDetection(Server server, string gameLogPath, Uri gameLogServerUri)
|
public GameLogEventDetection(Server server, string gameLogPath, Uri gameLogServerUri, IGameLogReader reader = null)
|
||||||
{
|
{
|
||||||
_gameLogFile = gameLogPath;
|
_reader = gameLogServerUri != null
|
||||||
_reader = gameLogServerUri != null ? new GameLogReaderHttp(gameLogServerUri, gameLogPath, server.EventParser) : _reader = new GameLogReader(gameLogPath, server.EventParser);
|
? reader ?? new GameLogReaderHttp(gameLogServerUri, gameLogPath, server.EventParser)
|
||||||
|
: reader ?? new GameLogReader(gameLogPath, server.EventParser);
|
||||||
_server = server;
|
_server = server;
|
||||||
_ignoreBots = server.Manager.GetApplicationSettings().Configuration().IgnoreBots;
|
_ignoreBots = server?.Manager.GetApplicationSettings().Configuration().IgnoreBots ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PollForChanges()
|
public async Task PollForChanges()
|
||||||
@ -52,7 +52,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
_server.Logger.WriteDebug("Stopped polling for changes");
|
_server.Logger.WriteDebug("Stopped polling for changes");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateLogEvents()
|
public async Task UpdateLogEvents()
|
||||||
{
|
{
|
||||||
long fileSize = _reader.Length;
|
long fileSize = _reader.Length;
|
||||||
|
|
||||||
@ -65,7 +65,10 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
// this makes the http log get pulled
|
// this makes the http log get pulled
|
||||||
if (fileDiff < 1 && fileSize != -1)
|
if (fileDiff < 1 && fileSize != -1)
|
||||||
|
{
|
||||||
|
previousFileSize = fileSize;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var events = await _reader.ReadEventsFromLog(_server, fileDiff, previousFileSize);
|
var events = await _reader.ReadEventsFromLog(_server, fileDiff, previousFileSize);
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
_parser = parser;
|
_parser = parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
public async Task<IEnumerable<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
||||||
{
|
{
|
||||||
// allocate the bytes for the new log lines
|
// allocate the bytes for the new log lines
|
||||||
List<string> logLines = new List<string>();
|
List<string> logLines = new List<string>();
|
||||||
|
@ -16,27 +16,27 @@ namespace IW4MAdmin.Application.IO
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class GameLogReaderHttp : IGameLogReader
|
class GameLogReaderHttp : IGameLogReader
|
||||||
{
|
{
|
||||||
readonly IEventParser Parser;
|
private readonly IEventParser _eventParser;
|
||||||
readonly IGameLogServer Api;
|
private readonly IGameLogServer _logServerApi;
|
||||||
readonly string logPath;
|
readonly string logPath;
|
||||||
private string lastKey = "next";
|
private string lastKey = "next";
|
||||||
|
|
||||||
public GameLogReaderHttp(Uri gameLogServerUri, string logPath, IEventParser parser)
|
public GameLogReaderHttp(Uri gameLogServerUri, string logPath, IEventParser parser)
|
||||||
{
|
{
|
||||||
this.logPath = logPath.ToBase64UrlSafeString(); ;
|
this.logPath = logPath.ToBase64UrlSafeString();
|
||||||
Parser = parser;
|
_eventParser = parser;
|
||||||
Api = RestClient.For<IGameLogServer>(gameLogServerUri);
|
_logServerApi = RestClient.For<IGameLogServer>(gameLogServerUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Length => -1;
|
public long Length => -1;
|
||||||
|
|
||||||
public int UpdateInterval => 500;
|
public int UpdateInterval => 500;
|
||||||
|
|
||||||
public async Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
public async Task<IEnumerable<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
||||||
{
|
{
|
||||||
var events = new List<GameEvent>();
|
var events = new List<GameEvent>();
|
||||||
string b64Path = logPath;
|
string b64Path = logPath;
|
||||||
var response = await Api.Log(b64Path, lastKey);
|
var response = await _logServerApi.Log(b64Path, lastKey);
|
||||||
lastKey = response.NextKey;
|
lastKey = response.NextKey;
|
||||||
|
|
||||||
if (!response.Success && string.IsNullOrEmpty(lastKey))
|
if (!response.Success && string.IsNullOrEmpty(lastKey))
|
||||||
@ -48,17 +48,17 @@ namespace IW4MAdmin.Application.IO
|
|||||||
else if (!string.IsNullOrWhiteSpace(response.Data))
|
else if (!string.IsNullOrWhiteSpace(response.Data))
|
||||||
{
|
{
|
||||||
// parse each line
|
// parse each line
|
||||||
foreach (string eventLine in response.Data
|
var lines = response.Data
|
||||||
.Split(Environment.NewLine)
|
.Split(Environment.NewLine)
|
||||||
.Where(_line => _line.Length > 0))
|
.Where(_line => _line.Length > 0);
|
||||||
|
|
||||||
|
foreach (string eventLine in lines)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gameEvent = Parser.GenerateGameEvent(eventLine);
|
// this trim end should hopefully fix the nasty runaway regex
|
||||||
|
var gameEvent = _eventParser.GenerateGameEvent(eventLine.TrimEnd('\r'));
|
||||||
events.Add(gameEvent);
|
events.Add(gameEvent);
|
||||||
#if DEBUG == true
|
|
||||||
server.Logger.WriteDebug($"Parsed event with id {gameEvent.Id} from http");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -25,7 +25,7 @@ namespace IW4MAdmin
|
|||||||
public class IW4MServer : Server
|
public class IW4MServer : Server
|
||||||
{
|
{
|
||||||
private static readonly SharedLibraryCore.Localization.TranslationLookup loc = Utilities.CurrentLocalization.LocalizationIndex;
|
private static readonly SharedLibraryCore.Localization.TranslationLookup loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
private GameLogEventDetection LogEvent;
|
public GameLogEventDetection LogEvent;
|
||||||
private readonly ITranslationLookup _translationLookup;
|
private readonly ITranslationLookup _translationLookup;
|
||||||
private const int REPORT_FLAG_COUNT = 4;
|
private const int REPORT_FLAG_COUNT = 4;
|
||||||
private int lastGameTime = 0;
|
private int lastGameTime = 0;
|
||||||
@ -891,8 +891,8 @@ namespace IW4MAdmin
|
|||||||
EventParser = Manager.AdditionalEventParsers
|
EventParser = Manager.AdditionalEventParsers
|
||||||
.FirstOrDefault(_parser => _parser.Version == ServerConfig.EventParserVersion);
|
.FirstOrDefault(_parser => _parser.Version == ServerConfig.EventParserVersion);
|
||||||
|
|
||||||
RconParser = RconParser ?? new BaseRConParser();
|
RconParser = RconParser ?? Manager.AdditionalRConParsers[0];
|
||||||
EventParser = EventParser ?? new BaseEventParser();
|
EventParser = EventParser ?? Manager.AdditionalEventParsers[0];
|
||||||
|
|
||||||
RemoteConnection.SetConfiguration(RconParser.Configuration);
|
RemoteConnection.SetConfiguration(RconParser.Configuration);
|
||||||
|
|
||||||
@ -949,6 +949,14 @@ namespace IW4MAdmin
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var website = await this.GetDvarAsync<string>("_website");
|
var website = await this.GetDvarAsync<string>("_website");
|
||||||
|
|
||||||
|
// this occurs for games that don't give us anything back when
|
||||||
|
// the dvar is not set
|
||||||
|
if (string.IsNullOrWhiteSpace(website.Value))
|
||||||
|
{
|
||||||
|
throw new DvarException("value is empty");
|
||||||
|
}
|
||||||
|
|
||||||
Website = website.Value;
|
Website = website.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using IW4MAdmin.Application.Factories;
|
using IW4MAdmin.Application.EventParsers;
|
||||||
|
using IW4MAdmin.Application.Factories;
|
||||||
using IW4MAdmin.Application.Helpers;
|
using IW4MAdmin.Application.Helpers;
|
||||||
using IW4MAdmin.Application.IO;
|
|
||||||
using IW4MAdmin.Application.Migration;
|
using IW4MAdmin.Application.Migration;
|
||||||
using IW4MAdmin.Application.Misc;
|
using IW4MAdmin.Application.Misc;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -87,7 +87,7 @@ namespace IW4MAdmin.Application
|
|||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
string failMessage = translationLookup == null ? "Failed to initalize IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"];
|
string failMessage = translationLookup == null ? "Failed to initalize IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"];
|
||||||
string exitMessage = translationLookup == null ? "Press any key to exit..." : translationLookup["MANAGER_EXIT"];
|
string exitMessage = translationLookup == null ? "Press enter to exit..." : translationLookup["MANAGER_EXIT"];
|
||||||
|
|
||||||
Console.WriteLine(failMessage);
|
Console.WriteLine(failMessage);
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(exitMessage);
|
Console.WriteLine(exitMessage);
|
||||||
Console.ReadKey();
|
await Console.In.ReadAsync(new char[1], 0, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
while (!ServerManager.CancellationToken.IsCancellationRequested)
|
while (!ServerManager.CancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
lastCommand = Console.ReadLine();
|
lastCommand = await Console.In.ReadLineAsync();
|
||||||
|
|
||||||
if (lastCommand?.Length > 0)
|
if (lastCommand?.Length > 0)
|
||||||
{
|
{
|
||||||
@ -282,6 +282,8 @@ namespace IW4MAdmin.Application
|
|||||||
.AddSingleton<IRConConnectionFactory, RConConnectionFactory>()
|
.AddSingleton<IRConConnectionFactory, RConConnectionFactory>()
|
||||||
.AddSingleton<IGameServerInstanceFactory, GameServerInstanceFactory>()
|
.AddSingleton<IGameServerInstanceFactory, GameServerInstanceFactory>()
|
||||||
.AddSingleton<IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
|
.AddSingleton<IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
|
||||||
|
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
||||||
|
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
||||||
.AddSingleton(_serviceProvider =>
|
.AddSingleton(_serviceProvider =>
|
||||||
{
|
{
|
||||||
var config = _serviceProvider.GetRequiredService<IConfigurationHandler<ApplicationConfiguration>>().Configuration();
|
var config = _serviceProvider.GetRequiredService<IConfigurationHandler<ApplicationConfiguration>>().Configuration();
|
||||||
|
21
Application/Misc/ParserMatchResult.cs
Normal file
21
Application/Misc/ParserMatchResult.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// implementation of the IMatchResult
|
||||||
|
/// used to hold matching results
|
||||||
|
/// </summary>
|
||||||
|
public class ParserMatchResult : IMatchResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// array of matched pattern groups
|
||||||
|
/// </summary>
|
||||||
|
public string[] Values { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// indicates if the match succeeded
|
||||||
|
/// </summary>
|
||||||
|
public bool Success { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -12,15 +12,11 @@ using static SharedLibraryCore.Server;
|
|||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
namespace IW4MAdmin.Application.RconParsers
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
public class BaseRConParser : IRConParser
|
public class BaseRConParser : IRConParser
|
||||||
#else
|
|
||||||
class BaseRConParser : IRConParser
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
public BaseRConParser()
|
public BaseRConParser(IParserRegexFactory parserRegexFactory)
|
||||||
{
|
{
|
||||||
Configuration = new DynamicRConParserConfiguration()
|
Configuration = new DynamicRConParserConfiguration(parserRegexFactory)
|
||||||
{
|
{
|
||||||
CommandPrefixes = new CommandPrefix()
|
CommandPrefixes = new CommandPrefix()
|
||||||
{
|
{
|
||||||
@ -90,7 +86,6 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
|
|
||||||
string removeTrailingColorCode(string input) => Regex.Replace(input, @"\^7$", "");
|
string removeTrailingColorCode(string input) => Regex.Replace(input, @"\^7$", "");
|
||||||
|
|
||||||
|
|
||||||
value = removeTrailingColorCode(value);
|
value = removeTrailingColorCode(value);
|
||||||
defaultValue = removeTrailingColorCode(defaultValue);
|
defaultValue = removeTrailingColorCode(defaultValue);
|
||||||
latchedValue = removeTrailingColorCode(latchedValue);
|
latchedValue = removeTrailingColorCode(latchedValue);
|
||||||
@ -134,7 +129,11 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
|
|
||||||
public async Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue)
|
public async Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue)
|
||||||
{
|
{
|
||||||
return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, $"{dvarName} {dvarValue}")).Length > 0;
|
string dvarString = (dvarValue is string str)
|
||||||
|
? $"{dvarName} \"{str}\""
|
||||||
|
: $"{dvarName} {dvarValue.ToString()}";
|
||||||
|
|
||||||
|
return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, dvarString)).Length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<EFClient> ClientsFromStatus(string[] Status)
|
private List<EFClient> ClientsFromStatus(string[] Status)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace IW4MAdmin.Application.RconParsers
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.RconParsers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// empty implementation of the IW4RConParser
|
/// empty implementation of the IW4RConParser
|
||||||
@ -6,5 +8,8 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
sealed internal class DynamicRConParser : BaseRConParser
|
sealed internal class DynamicRConParser : BaseRConParser
|
||||||
{
|
{
|
||||||
|
public DynamicRConParser(IParserRegexFactory parserRegexFactory) : base(parserRegexFactory)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using SharedLibraryCore.Interfaces;
|
using IW4MAdmin.Application.Factories;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.RCon;
|
using SharedLibraryCore.RCon;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
@ -11,11 +12,18 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
sealed internal class DynamicRConParserConfiguration : IRConParserConfiguration
|
sealed internal class DynamicRConParserConfiguration : IRConParserConfiguration
|
||||||
{
|
{
|
||||||
public CommandPrefix CommandPrefixes { get; set; }
|
public CommandPrefix CommandPrefixes { get; set; }
|
||||||
public ParserRegex Status { get; set; } = new ParserRegex();
|
public ParserRegex Status { get; set; }
|
||||||
public ParserRegex MapStatus { get; set; } = new ParserRegex();
|
public ParserRegex MapStatus { get; set; }
|
||||||
public ParserRegex Dvar { get; set; } = new ParserRegex();
|
public ParserRegex Dvar { get; set; }
|
||||||
public string ServerNotRunningResponse { get; set; }
|
public string ServerNotRunningResponse { get; set; }
|
||||||
public bool WaitForResponse { get; set; } = true;
|
public bool WaitForResponse { get; set; } = true;
|
||||||
public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber;
|
public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber;
|
||||||
|
|
||||||
|
public DynamicRConParserConfiguration(IParserRegexFactory parserRegexFactory)
|
||||||
|
{
|
||||||
|
Status = parserRegexFactory.CreateParserRegex();
|
||||||
|
MapStatus = parserRegexFactory.CreateParserRegex();
|
||||||
|
Dvar = parserRegexFactory.CreateParserRegex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using IW4MAdmin.Application;
|
using IW4MAdmin.Application;
|
||||||
|
using IW4MAdmin.Application.Factories;
|
||||||
using IW4MAdmin.Application.Misc;
|
using IW4MAdmin.Application.Misc;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
@ -42,7 +43,6 @@ namespace Tests
|
|||||||
|
|
||||||
Manager.ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("test");
|
Manager.ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("test");
|
||||||
Manager.ConfigHandler.Set(config);
|
Manager.ConfigHandler.Set(config);
|
||||||
Manager.AdditionalRConParsers.Add(new TestRconParser());
|
|
||||||
|
|
||||||
Manager.Init().Wait();
|
Manager.Init().Wait();
|
||||||
|
|
||||||
|
@ -10,6 +10,11 @@ namespace Tests
|
|||||||
{
|
{
|
||||||
class TestRconParser : IW4MAdmin.Application.RconParsers.BaseRConParser
|
class TestRconParser : IW4MAdmin.Application.RconParsers.BaseRConParser
|
||||||
{
|
{
|
||||||
|
public TestRconParser(IParserRegexFactory f) : base(f)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public int FakeClientCount { get; set; }
|
public int FakeClientCount { get; set; }
|
||||||
public List<EFClient> FakeClients { get; set; } = new List<EFClient>();
|
public List<EFClient> FakeClients { get; set; } = new List<EFClient>();
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@{
|
@{
|
||||||
Layout = null;
|
Layout = null;
|
||||||
var loc = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex.Set;
|
var loc = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex.Set;
|
||||||
double getDeviation(double deviations) => Math.Pow(Math.E, 5.0813 + (deviations * 0.8694));
|
double getDeviation(double deviations) => Math.Pow(Math.E, 5.259 + (deviations * 0.812));
|
||||||
string rankIcon(double elo)
|
string rankIcon(double elo)
|
||||||
{
|
{
|
||||||
if (elo >= getDeviation(-0.75) && elo < getDeviation(1.25))
|
if (elo >= getDeviation(-0.75) && elo < getDeviation(1.25))
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
@ -41,10 +40,21 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
AdditionalGroup = 200
|
AdditionalGroup = 200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IParserPatternMatcher PatternMatcher { get; private set; }
|
||||||
|
|
||||||
|
private string pattern;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the regular expression groups that will be mapped to group types
|
/// stores the regular expression groups that will be mapped to group types
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Pattern { get; set; }
|
public string Pattern
|
||||||
|
{
|
||||||
|
get => pattern;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
pattern = value;
|
||||||
|
PatternMatcher.Compile(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the mapping from group type to group index in the regular expression
|
/// stores the mapping from group type to group index in the regular expression
|
||||||
@ -90,9 +100,10 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParserRegex()
|
public ParserRegex(IParserPatternMatcher pattern)
|
||||||
{
|
{
|
||||||
GroupMapping = new Dictionary<GroupType, int>();
|
GroupMapping = new Dictionary<GroupType, int>();
|
||||||
|
PatternMatcher = pattern;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,11 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
ParserRegex Action { get; set; }
|
ParserRegex Action { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// stores the regex information for the time prefix in game log
|
||||||
|
/// </summary>
|
||||||
|
ParserRegex Time { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// indicates the format expected for parsed guids
|
/// indicates the format expected for parsed guids
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
@ -17,11 +15,13 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <param name="fileSizeDiff"></param>
|
/// <param name="fileSizeDiff"></param>
|
||||||
/// <param name="startPosition"></param>
|
/// <param name="startPosition"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition);
|
Task<IEnumerable<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how long the log file is
|
/// how long the log file is
|
||||||
/// </summary>
|
/// </summary>
|
||||||
long Length { get; }
|
long Length { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how often to poll the log file
|
/// how often to poll the log file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
18
SharedLibraryCore/Interfaces/IMatchResult.cs
Normal file
18
SharedLibraryCore/Interfaces/IMatchResult.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// represents a pattern match result
|
||||||
|
/// </summary>
|
||||||
|
public interface IMatchResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// array of matched pattern groups
|
||||||
|
/// </summary>
|
||||||
|
string[] Values { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// indicates if the match succeeded
|
||||||
|
/// </summary>
|
||||||
|
bool Success { get; set; }
|
||||||
|
}
|
||||||
|
}
|
21
SharedLibraryCore/Interfaces/IParserPatternMatcher.cs
Normal file
21
SharedLibraryCore/Interfaces/IParserPatternMatcher.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// defines the capabilities of a parser pattern
|
||||||
|
/// </summary>
|
||||||
|
public interface IParserPatternMatcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// converts input string into pattern groups
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">input string</param>
|
||||||
|
/// <returns>group matches</returns>
|
||||||
|
IMatchResult Match(string input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// compiles the pattern to be used for matching
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern"></param>
|
||||||
|
void Compile(string pattern);
|
||||||
|
}
|
||||||
|
}
|
14
SharedLibraryCore/Interfaces/IParserRegexFactory.cs
Normal file
14
SharedLibraryCore/Interfaces/IParserRegexFactory.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// defines the capabilities of the parser regex factory
|
||||||
|
/// </summary>
|
||||||
|
public interface IParserRegexFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// creates a new ParserRegex instance
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>ParserRegex instance</returns>
|
||||||
|
ParserRegex CreateParserRegex();
|
||||||
|
}
|
||||||
|
}
|
@ -46,30 +46,30 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FluentValidation" Version="8.6.1" />
|
<PackageReference Include="FluentValidation" Version="8.6.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.1">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.3">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="Npgsql" Version="4.1.3" />
|
<PackageReference Include="Npgsql" Version="4.1.3.1" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.1.2" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.3" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
|
||||||
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(Configuration)'=='Debug'">
|
<ItemGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Update="Files\GameEvents.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Update="Files\T6Game.log">
|
<None Update="Files\T6Game.log">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
58
Tests/ApplicationTests/BaseEventParserTests.cs
Normal file
58
Tests/ApplicationTests/BaseEventParserTests.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using ApplicationTests.Fixtures;
|
||||||
|
using IW4MAdmin.Application.EventParsers;
|
||||||
|
using IW4MAdmin.Application.Factories;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ApplicationTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class BaseEventParserTests
|
||||||
|
{
|
||||||
|
private EventLogTest eventLogData;
|
||||||
|
private IServiceProvider serviceProvider;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
eventLogData = JsonConvert.DeserializeObject<EventLogTest>(System.IO.File.ReadAllText("Files/GameEvents.json"));
|
||||||
|
serviceProvider = new ServiceCollection()
|
||||||
|
.AddSingleton<BaseEventParser>()
|
||||||
|
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
||||||
|
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
||||||
|
.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestParsesAllEventData()
|
||||||
|
{
|
||||||
|
var eventParser = serviceProvider.GetService<BaseEventParser>();
|
||||||
|
|
||||||
|
void AssertMatch(GameEvent src, LogEvent expected)
|
||||||
|
{
|
||||||
|
Assert.AreEqual(expected.ExpectedEventType, src.Type);
|
||||||
|
Assert.AreEqual(expected.ExpectedData, src.Data);
|
||||||
|
Assert.AreEqual(expected.ExpectedMessage, src.Message);
|
||||||
|
Assert.AreEqual(expected.ExpectedTime, src.GameTime);
|
||||||
|
|
||||||
|
//Assert.AreEqual(expected.ExpectedOriginClientName, src.Origin?.Name);
|
||||||
|
Assert.AreEqual(expected.ExpectedOriginClientNumber, src.Origin?.ClientNumber);
|
||||||
|
Assert.AreEqual(expected.ExpectedOriginNetworkId, src.Origin?.NetworkId.ToString("X"));
|
||||||
|
|
||||||
|
//Assert.AreEqual(expected.ExpectedTargetClientName, src.Target?.Name);
|
||||||
|
Assert.AreEqual(expected.ExpectedTargetClientNumber, src.Target?.ClientNumber);
|
||||||
|
Assert.AreEqual(expected.ExpectedTargetNetworkId, src.Target?.NetworkId.ToString("X"));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var e in eventLogData.Events)
|
||||||
|
{
|
||||||
|
var parsedEvent = eventParser.GenerateGameEvent(e.EventLine);
|
||||||
|
AssertMatch(parsedEvent, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
Tests/ApplicationTests/BaseRConParserTests.cs
Normal file
47
Tests/ApplicationTests/BaseRConParserTests.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using FakeItEasy;
|
||||||
|
using IW4MAdmin.Application.RconParsers;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace ApplicationTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class BaseRConParserTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void SetDvarAsync_FormatStringType()
|
||||||
|
{
|
||||||
|
var parser = new BaseRConParser(A.Fake<IParserRegexFactory>());
|
||||||
|
var connection = A.Fake<IRConConnection>();
|
||||||
|
|
||||||
|
parser.SetDvarAsync(connection, "test", "test").Wait();
|
||||||
|
|
||||||
|
A.CallTo(() => connection.SendQueryAsync(SharedLibraryCore.RCon.StaticHelpers.QueryType.SET_DVAR, "test \"test\""))
|
||||||
|
.MustHaveHappened();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetDvarAsync_FormatEmptyStringTypeIncludesQuotes()
|
||||||
|
{
|
||||||
|
var parser = new BaseRConParser(A.Fake<IParserRegexFactory>());
|
||||||
|
var connection = A.Fake<IRConConnection>();
|
||||||
|
|
||||||
|
parser.SetDvarAsync(connection, "test", "").Wait();
|
||||||
|
|
||||||
|
A.CallTo(() => connection.SendQueryAsync(SharedLibraryCore.RCon.StaticHelpers.QueryType.SET_DVAR, "test \"\""))
|
||||||
|
.MustHaveHappened();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetDvarAsync_FormatsNonString()
|
||||||
|
{
|
||||||
|
var parser = new BaseRConParser(A.Fake<IParserRegexFactory>());
|
||||||
|
var connection = A.Fake<IRConConnection>();
|
||||||
|
|
||||||
|
parser.SetDvarAsync(connection, "test", 123).Wait();
|
||||||
|
|
||||||
|
A.CallTo(() => connection.SendQueryAsync(SharedLibraryCore.RCon.StaticHelpers.QueryType.SET_DVAR, "test 123"))
|
||||||
|
.MustHaveHappened();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
Tests/ApplicationTests/Fixtures/EventLogTest.cs
Normal file
26
Tests/ApplicationTests/Fixtures/EventLogTest.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using static SharedLibraryCore.GameEvent;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
|
namespace ApplicationTests.Fixtures
|
||||||
|
{
|
||||||
|
class LogEvent
|
||||||
|
{
|
||||||
|
public Game Game { get; set; }
|
||||||
|
public string EventLine { get; set; }
|
||||||
|
public EventType ExpectedEventType { get; set; }
|
||||||
|
public string ExpectedData { get; set; }
|
||||||
|
public string ExpectedMessage { get; set; }
|
||||||
|
public string ExpectedOriginNetworkId { get; set; }
|
||||||
|
public int? ExpectedOriginClientNumber { get; set; }
|
||||||
|
public string ExpectedOriginClientName { get; set; }
|
||||||
|
public string ExpectedTargetNetworkId { get; set; }
|
||||||
|
public int? ExpectedTargetClientNumber { get; set; }
|
||||||
|
public string ExpectedTargetClientName { get; set; }
|
||||||
|
public int? ExpectedTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventLogTest
|
||||||
|
{
|
||||||
|
public LogEvent[] Events { get; set; }
|
||||||
|
}
|
||||||
|
}
|
42
Tests/ApplicationTests/IOTests.cs
Normal file
42
Tests/ApplicationTests/IOTests.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using FakeItEasy;
|
||||||
|
using IW4MAdmin.Application.IO;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ApplicationTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class IOTests
|
||||||
|
{
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GameLogEventDetection_WorksAfterFileSizeReset()
|
||||||
|
{
|
||||||
|
var reader = A.Fake<IGameLogReader>();
|
||||||
|
var detect = new GameLogEventDetection(null, "", A.Fake<Uri>(), reader);
|
||||||
|
|
||||||
|
A.CallTo(() => reader.Length)
|
||||||
|
.Returns(100)
|
||||||
|
.Once()
|
||||||
|
.Then
|
||||||
|
.Returns(200)
|
||||||
|
.Once()
|
||||||
|
.Then
|
||||||
|
.Returns(10)
|
||||||
|
.Once()
|
||||||
|
.Then
|
||||||
|
.Returns(100);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
await detect.UpdateLogEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
A.CallTo(() => reader.ReadEventsFromLog(A<Server>.Ignored, A<long>.Ignored, A<long>.Ignored))
|
||||||
|
.MustHaveHappenedTwiceExactly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,7 @@ namespace ApplicationTests
|
|||||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
||||||
|
|
||||||
var parser = new BaseEventParser();
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
|
|
||||||
var log = System.IO.File.ReadAllLines("Files\\T6MapRotation.log");
|
var log = System.IO.File.ReadAllLines("Files\\T6MapRotation.log");
|
||||||
@ -61,7 +61,7 @@ namespace ApplicationTests
|
|||||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
||||||
|
|
||||||
var parser = new BaseEventParser();
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
|
|
||||||
var log = System.IO.File.ReadAllLines("Files\\T6Game.log");
|
var log = System.IO.File.ReadAllLines("Files\\T6Game.log");
|
||||||
|
@ -56,7 +56,7 @@ namespace ApplicationTests
|
|||||||
A.Fake<ITranslationLookup>(),
|
A.Fake<ITranslationLookup>(),
|
||||||
A.Fake<IRConConnectionFactory>());
|
A.Fake<IRConConnectionFactory>());
|
||||||
|
|
||||||
var parser = new BaseEventParser();
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
|
|
||||||
var log = System.IO.File.ReadAllLines("Files\\T6GameStats.log");
|
var log = System.IO.File.ReadAllLines("Files\\T6GameStats.log");
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(Configuration)'=='Debug'">
|
<ItemGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user