Compare commits
7 Commits
2020.11.14
...
2.3-Prerel
Author | SHA1 | Date | |
---|---|---|---|
e56f574af4 | |||
513f495304 | |||
910faf427b | |||
9117440566 | |||
ad6b6a6465 | |||
eb8145a168 | |||
a560e05df8 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -244,4 +244,3 @@ launchSettings.json
|
|||||||
/Tests/ApplicationTests/Files/GameEvents.json
|
/Tests/ApplicationTests/Files/GameEvents.json
|
||||||
/Tests/ApplicationTests/Files/replay.json
|
/Tests/ApplicationTests/Files/replay.json
|
||||||
/GameLogServer/game_log_server_env
|
/GameLogServer/game_log_server_env
|
||||||
.idea/*
|
|
@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IW4MAdmin.Application.Misc;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using RestEase;
|
using RestEase;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
@ -37,13 +35,6 @@ namespace IW4MAdmin.Application.API.Master
|
|||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PluginSubscriptionContent
|
|
||||||
{
|
|
||||||
public string Content { get; set; }
|
|
||||||
public PluginType Type { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the capabilities of the master API
|
/// Defines the capabilities of the master API
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -72,8 +63,5 @@ namespace IW4MAdmin.Application.API.Master
|
|||||||
|
|
||||||
[Get("localization/{languageTag}")]
|
[Get("localization/{languageTag}")]
|
||||||
Task<SharedLibraryCore.Localization.Layout> GetLocalization([Path("languageTag")] string languageTag);
|
Task<SharedLibraryCore.Localization.Layout> GetLocalization([Path("languageTag")] string languageTag);
|
||||||
|
|
||||||
[Get("plugin_subscriptions")]
|
|
||||||
Task<IEnumerable<PluginSubscriptionContent>> GetPluginSubscription([Query("instance_id")] Guid instanceId, [Query("subscription_id")] string subscription_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
||||||
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
||||||
<Version>2020.0.0.0</Version>
|
<Version>2.3.2.0</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
<Company>Forever None</Company>
|
<Company>Forever None</Company>
|
||||||
<Product>IW4MAdmin</Product>
|
<Product>IW4MAdmin</Product>
|
||||||
@ -59,9 +59,6 @@
|
|||||||
<None Update="DefaultSettings.json">
|
<None Update="DefaultSettings.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="Configuration\LoggingConfiguration.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using IW4MAdmin.Application.EventParsers;
|
using IW4MAdmin.Application.API.Master;
|
||||||
|
using IW4MAdmin.Application.EventParsers;
|
||||||
using IW4MAdmin.Application.Extensions;
|
using IW4MAdmin.Application.Extensions;
|
||||||
using IW4MAdmin.Application.Misc;
|
using IW4MAdmin.Application.Misc;
|
||||||
using IW4MAdmin.Application.RconParsers;
|
using IW4MAdmin.Application.RconParsers;
|
||||||
@ -8,9 +9,11 @@ using SharedLibraryCore.Configuration;
|
|||||||
using SharedLibraryCore.Configuration.Validation;
|
using SharedLibraryCore.Configuration.Validation;
|
||||||
using SharedLibraryCore.Database;
|
using SharedLibraryCore.Database;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Exceptions;
|
using SharedLibraryCore.Exceptions;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using SharedLibraryCore.QueryHelper;
|
||||||
using SharedLibraryCore.Services;
|
using SharedLibraryCore.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
@ -21,12 +24,7 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
using static SharedLibraryCore.GameEvent;
|
using static SharedLibraryCore.GameEvent;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
using ObsoleteLogger = SharedLibraryCore.Interfaces.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
{
|
{
|
||||||
@ -34,7 +32,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
private readonly ConcurrentBag<Server> _servers;
|
private readonly ConcurrentBag<Server> _servers;
|
||||||
public List<Server> Servers => _servers.OrderByDescending(s => s.ClientNum).ToList();
|
public List<Server> Servers => _servers.OrderByDescending(s => s.ClientNum).ToList();
|
||||||
[Obsolete] public ObsoleteLogger Logger => _serviceProvider.GetRequiredService<ObsoleteLogger>();
|
public ILogger Logger => GetLogger(0);
|
||||||
public bool IsRunning { get; private set; }
|
public bool IsRunning { get; private set; }
|
||||||
public bool IsInitialized { get; private set; }
|
public bool IsInitialized { get; private set; }
|
||||||
public DateTime StartTime { get; private set; }
|
public DateTime StartTime { get; private set; }
|
||||||
@ -56,6 +54,7 @@ namespace IW4MAdmin.Application
|
|||||||
readonly PenaltyService PenaltySvc;
|
readonly PenaltyService PenaltySvc;
|
||||||
public IConfigurationHandler<ApplicationConfiguration> ConfigHandler;
|
public IConfigurationHandler<ApplicationConfiguration> ConfigHandler;
|
||||||
readonly IPageList PageList;
|
readonly IPageList PageList;
|
||||||
|
private readonly Dictionary<long, ILogger> _loggers = new Dictionary<long, ILogger>();
|
||||||
private readonly IMetaService _metaService;
|
private readonly IMetaService _metaService;
|
||||||
private readonly TimeSpan _throttleTimeout = new TimeSpan(0, 1, 0);
|
private readonly TimeSpan _throttleTimeout = new TimeSpan(0, 1, 0);
|
||||||
private readonly CancellationTokenSource _tokenSource;
|
private readonly CancellationTokenSource _tokenSource;
|
||||||
@ -69,33 +68,30 @@ namespace IW4MAdmin.Application
|
|||||||
private readonly IScriptCommandFactory _scriptCommandFactory;
|
private readonly IScriptCommandFactory _scriptCommandFactory;
|
||||||
private readonly IMetaRegistration _metaRegistration;
|
private readonly IMetaRegistration _metaRegistration;
|
||||||
private readonly IScriptPluginServiceResolver _scriptPluginServiceResolver;
|
private readonly IScriptPluginServiceResolver _scriptPluginServiceResolver;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
private readonly ChangeHistoryService _changeHistoryService;
|
|
||||||
private readonly ApplicationConfiguration _appConfig;
|
|
||||||
|
|
||||||
public ApplicationManager(ILogger<ApplicationManager> 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, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
||||||
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, IMetaService metaService,
|
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, IMetaService metaService,
|
||||||
IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver, ClientService clientService, IServiceProvider serviceProvider,
|
IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver)
|
||||||
ChangeHistoryService changeHistoryService, ApplicationConfiguration appConfig)
|
|
||||||
{
|
{
|
||||||
MiddlewareActionHandler = actionHandler;
|
MiddlewareActionHandler = actionHandler;
|
||||||
_servers = new ConcurrentBag<Server>();
|
_servers = new ConcurrentBag<Server>();
|
||||||
MessageTokens = new List<MessageToken>();
|
MessageTokens = new List<MessageToken>();
|
||||||
ClientSvc = clientService;
|
ClientSvc = new ClientService(contextFactory);
|
||||||
AliasSvc = new AliasService();
|
AliasSvc = new AliasService();
|
||||||
PenaltySvc = new PenaltyService();
|
PenaltySvc = new PenaltyService();
|
||||||
ConfigHandler = appConfigHandler;
|
ConfigHandler = appConfigHandler;
|
||||||
StartTime = DateTime.UtcNow;
|
StartTime = DateTime.UtcNow;
|
||||||
PageList = new PageList();
|
PageList = new PageList();
|
||||||
AdditionalEventParsers = new List<IEventParser>() { new BaseEventParser(parserRegexFactory, logger, _appConfig) };
|
AdditionalEventParsers = new List<IEventParser>() { new BaseEventParser(parserRegexFactory, logger, appConfigHandler.Configuration()) };
|
||||||
AdditionalRConParsers = new List<IRConParser>() { new BaseRConParser(serviceProvider.GetRequiredService<ILogger<BaseRConParser>>(), parserRegexFactory) };
|
AdditionalRConParsers = new List<IRConParser>() { new BaseRConParser(parserRegexFactory) };
|
||||||
TokenAuthenticator = new TokenAuthentication();
|
TokenAuthenticator = new TokenAuthentication();
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_metaService = metaService;
|
_metaService = metaService;
|
||||||
_tokenSource = new CancellationTokenSource();
|
_tokenSource = new CancellationTokenSource();
|
||||||
|
_loggers.Add(0, logger);
|
||||||
_commands = commands.ToList();
|
_commands = commands.ToList();
|
||||||
_translationLookup = translationLookup;
|
_translationLookup = translationLookup;
|
||||||
_commandConfiguration = commandConfiguration;
|
_commandConfiguration = commandConfiguration;
|
||||||
@ -106,9 +102,6 @@ namespace IW4MAdmin.Application
|
|||||||
_scriptCommandFactory = scriptCommandFactory;
|
_scriptCommandFactory = scriptCommandFactory;
|
||||||
_metaRegistration = metaRegistration;
|
_metaRegistration = metaRegistration;
|
||||||
_scriptPluginServiceResolver = scriptPluginServiceResolver;
|
_scriptPluginServiceResolver = scriptPluginServiceResolver;
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
_changeHistoryService = changeHistoryService;
|
|
||||||
_appConfig = appConfig;
|
|
||||||
Plugins = plugins;
|
Plugins = plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +109,10 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public async Task ExecuteEvent(GameEvent newEvent)
|
public async Task ExecuteEvent(GameEvent newEvent)
|
||||||
{
|
{
|
||||||
|
#if DEBUG == true
|
||||||
|
Logger.WriteDebug($"Entering event process for {newEvent.Id}");
|
||||||
|
#endif
|
||||||
|
|
||||||
// the event has failed already
|
// the event has failed already
|
||||||
if (newEvent.Failed)
|
if (newEvent.Failed)
|
||||||
{
|
{
|
||||||
@ -127,17 +124,22 @@ namespace IW4MAdmin.Application
|
|||||||
await newEvent.Owner.ExecuteEvent(newEvent);
|
await newEvent.Owner.ExecuteEvent(newEvent);
|
||||||
|
|
||||||
// save the event info to the database
|
// save the event info to the database
|
||||||
await _changeHistoryService.Add(newEvent);
|
var changeHistorySvc = new ChangeHistoryService();
|
||||||
|
await changeHistorySvc.Add(newEvent);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Logger.WriteDebug($"Processed event with id {newEvent.Id}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (TaskCanceledException)
|
catch (TaskCanceledException)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Received quit signal for event id {eventId}, so we are aborting early", newEvent.Id);
|
Logger.WriteInfo($"Received quit signal for event id {newEvent.Id}, so we are aborting early");
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Received quit signal for event id {eventId}, so we are aborting early", newEvent.Id);
|
Logger.WriteInfo($"Received quit signal for event id {newEvent.Id}, so we are aborting early");
|
||||||
}
|
}
|
||||||
|
|
||||||
// this happens if a plugin requires login
|
// this happens if a plugin requires login
|
||||||
@ -150,35 +152,31 @@ namespace IW4MAdmin.Application
|
|||||||
catch (NetworkException ex)
|
catch (NetworkException ex)
|
||||||
{
|
{
|
||||||
newEvent.FailReason = EventFailReason.Exception;
|
newEvent.FailReason = EventFailReason.Exception;
|
||||||
using (LogContext.PushProperty("Server", newEvent.Owner?.ToString()))
|
Logger.WriteError(ex.Message);
|
||||||
{
|
Logger.WriteDebug(ex.GetExceptionInfo());
|
||||||
_logger.LogError(ex, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (ServerException ex)
|
catch (ServerException ex)
|
||||||
{
|
{
|
||||||
newEvent.FailReason = EventFailReason.Exception;
|
newEvent.FailReason = EventFailReason.Exception;
|
||||||
using (LogContext.PushProperty("Server", newEvent.Owner?.ToString()))
|
Logger.WriteWarning(ex.Message);
|
||||||
{
|
|
||||||
_logger.LogError(ex, ex.Message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
newEvent.FailReason = EventFailReason.Exception;
|
newEvent.FailReason = EventFailReason.Exception;
|
||||||
Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"].FormatExt(newEvent.Owner));
|
Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"].FormatExt(newEvent.Owner));
|
||||||
using (LogContext.PushProperty("Server", newEvent.Owner?.ToString()))
|
Logger.WriteDebug(ex.GetExceptionInfo());
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Unexpected exception");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
// tell anyone waiting for the output that we're done
|
// tell anyone waiting for the output that we're done
|
||||||
newEvent.Complete();
|
newEvent.Complete();
|
||||||
OnGameEventExecuted?.Invoke(this, newEvent);
|
OnGameEventExecuted?.Invoke(this, newEvent);
|
||||||
|
|
||||||
|
#if DEBUG == true
|
||||||
|
Logger.WriteDebug($"Exiting event process for {newEvent.Id}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<Server> GetServers()
|
public IList<Server> GetServers()
|
||||||
@ -228,14 +226,17 @@ namespace IW4MAdmin.Application
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await server.ProcessUpdatesAsync(_tokenSource.Token);
|
await server.ProcessUpdatesAsync(_tokenSource.Token);
|
||||||
|
|
||||||
|
if (server.Throttled)
|
||||||
|
{
|
||||||
|
await Task.Delay((int)_throttleTimeout.TotalMilliseconds, _tokenSource.Token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", server.ToString()))
|
Logger.WriteWarning($"Failed to update status for {server}");
|
||||||
{
|
Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
_logger.LogError(e, "Failed to update status");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@ -244,7 +245,12 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
#if DEBUG
|
||||||
|
Logger.WriteDebug($"{runningUpdateTasks.Count} servers queued for stats updates");
|
||||||
|
ThreadPool.GetMaxThreads(out int workerThreads, out int n);
|
||||||
|
ThreadPool.GetAvailableThreads(out int availableThreads, out int m);
|
||||||
|
Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
||||||
|
#endif
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(ConfigHandler.Configuration().RConPollRate, _tokenSource.Token);
|
await Task.Delay(ConfigHandler.Configuration().RConPollRate, _tokenSource.Token);
|
||||||
@ -283,8 +289,8 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_ERROR"].FormatExt(scriptPlugin.Name));
|
Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_ERROR"].FormatExt(scriptPlugin.Name));
|
||||||
_logger.LogError(ex, "Could not properly load plugin {plugin}", scriptPlugin.Name);
|
Logger.WriteDebug(ex.Message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -297,29 +303,32 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"{_translationLookup["SERVER_ERROR_PLUGIN"]} {plugin.Name}");
|
Logger.WriteError($"{_translationLookup["SERVER_ERROR_PLUGIN"]} {plugin.Name}");
|
||||||
|
Logger.WriteDebug(ex.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region CONFIG
|
#region CONFIG
|
||||||
|
var config = ConfigHandler.Configuration();
|
||||||
|
|
||||||
// copy over default config if it doesn't exist
|
// copy over default config if it doesn't exist
|
||||||
if (!_appConfig.Servers?.Any() ?? true)
|
if (config == null)
|
||||||
{
|
{
|
||||||
var defaultConfig = new BaseConfigurationHandler<DefaultConfiguration>("DefaultSettings").Configuration();
|
var defaultConfig = new BaseConfigurationHandler<DefaultConfiguration>("DefaultSettings").Configuration();
|
||||||
//ConfigHandler.Set((ApplicationConfiguration)new ApplicationConfiguration().Generate());
|
ConfigHandler.Set((ApplicationConfiguration)new ApplicationConfiguration().Generate());
|
||||||
//var newConfig = ConfigHandler.Configuration();
|
var newConfig = ConfigHandler.Configuration();
|
||||||
|
|
||||||
_appConfig.AutoMessages = defaultConfig.AutoMessages;
|
newConfig.AutoMessages = defaultConfig.AutoMessages;
|
||||||
_appConfig.GlobalRules = defaultConfig.GlobalRules;
|
newConfig.GlobalRules = defaultConfig.GlobalRules;
|
||||||
_appConfig.Maps = defaultConfig.Maps;
|
newConfig.Maps = defaultConfig.Maps;
|
||||||
_appConfig.DisallowedClientNames = defaultConfig.DisallowedClientNames;
|
newConfig.DisallowedClientNames = defaultConfig.DisallowedClientNames;
|
||||||
_appConfig.QuickMessages = defaultConfig.QuickMessages;
|
newConfig.QuickMessages = defaultConfig.QuickMessages;
|
||||||
|
|
||||||
//if (newConfig.Servers == null)
|
if (newConfig.Servers == null)
|
||||||
{
|
{
|
||||||
ConfigHandler.Set(_appConfig);
|
ConfigHandler.Set(newConfig);
|
||||||
_appConfig.Servers = new ServerConfiguration[1];
|
newConfig.Servers = new ServerConfiguration[1];
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -334,29 +343,30 @@ namespace IW4MAdmin.Application
|
|||||||
serverConfig.AddEventParser(parser);
|
serverConfig.AddEventParser(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
_appConfig.Servers = _appConfig.Servers.Where(_servers => _servers != null).Append((ServerConfiguration)serverConfig.Generate()).ToArray();
|
newConfig.Servers = newConfig.Servers.Where(_servers => _servers != null).Append((ServerConfiguration)serverConfig.Generate()).ToArray();
|
||||||
} while (Utilities.PromptBool(_translationLookup["SETUP_SERVER_SAVE"]));
|
} while (Utilities.PromptBool(_translationLookup["SETUP_SERVER_SAVE"]));
|
||||||
|
|
||||||
|
config = newConfig;
|
||||||
await ConfigHandler.Save();
|
await ConfigHandler.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_appConfig.Id))
|
if (string.IsNullOrEmpty(config.Id))
|
||||||
{
|
{
|
||||||
_appConfig.Id = Guid.NewGuid().ToString();
|
config.Id = Guid.NewGuid().ToString();
|
||||||
await ConfigHandler.Save();
|
await ConfigHandler.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_appConfig.WebfrontBindUrl))
|
if (string.IsNullOrEmpty(config.WebfrontBindUrl))
|
||||||
{
|
{
|
||||||
_appConfig.WebfrontBindUrl = "http://0.0.0.0:1624";
|
config.WebfrontBindUrl = "http://0.0.0.0:1624";
|
||||||
await ConfigHandler.Save();
|
await ConfigHandler.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
var validator = new ApplicationConfigurationValidator();
|
var validator = new ApplicationConfigurationValidator();
|
||||||
var validationResult = validator.Validate(_appConfig);
|
var validationResult = validator.Validate(config);
|
||||||
|
|
||||||
if (!validationResult.IsValid)
|
if (!validationResult.IsValid)
|
||||||
{
|
{
|
||||||
@ -367,7 +377,7 @@ namespace IW4MAdmin.Application
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var serverConfig in _appConfig.Servers)
|
foreach (var serverConfig in config.Servers)
|
||||||
{
|
{
|
||||||
Migration.ConfigurationMigration.ModifyLogPath020919(serverConfig);
|
Migration.ConfigurationMigration.ModifyLogPath020919(serverConfig);
|
||||||
|
|
||||||
@ -389,13 +399,13 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_appConfig.Servers.Length == 0)
|
if (config.Servers.Length == 0)
|
||||||
{
|
{
|
||||||
throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid");
|
throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
Utilities.EncodingType = Encoding.GetEncoding(!string.IsNullOrEmpty(_appConfig.CustomParserEncoding) ? _appConfig.CustomParserEncoding : "windows-1252");
|
Utilities.EncodingType = Encoding.GetEncoding(!string.IsNullOrEmpty(config.CustomParserEncoding) ? config.CustomParserEncoding : "windows-1252");
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -430,8 +440,8 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
// this is because I want to store the command prefix in IW4MAdminSettings, but can't easily
|
// this is because I want to store the command prefix in IW4MAdminSettings, but can't easily
|
||||||
// inject it to all the places that need it
|
// inject it to all the places that need it
|
||||||
cmdConfig.CommandPrefix = _appConfig.CommandPrefix;
|
cmdConfig.CommandPrefix = config.CommandPrefix;
|
||||||
cmdConfig.BroadcastCommandPrefix = _appConfig.BroadcastCommandPrefix;
|
cmdConfig.BroadcastCommandPrefix = config.BroadcastCommandPrefix;
|
||||||
|
|
||||||
foreach (var cmd in commandsToAddToConfig)
|
foreach (var cmd in commandsToAddToConfig)
|
||||||
{
|
{
|
||||||
@ -462,7 +472,6 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
Console.WriteLine(_translationLookup["MANAGER_COMMUNICATION_INFO"]);
|
|
||||||
await InitializeServers();
|
await InitializeServers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,17 +487,13 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
// todo: this might not always be an IW4MServer
|
// todo: this might not always be an IW4MServer
|
||||||
var ServerInstance = _serverInstanceFactory.CreateServer(Conf, this) as IW4MServer;
|
var ServerInstance = _serverInstanceFactory.CreateServer(Conf, this) as IW4MServer;
|
||||||
using (LogContext.PushProperty("Server", ServerInstance.ToString()))
|
await ServerInstance.Initialize();
|
||||||
{
|
|
||||||
_logger.LogInformation("Beginning server communication initialization");
|
|
||||||
await ServerInstance.Initialize();
|
|
||||||
|
|
||||||
_servers.Add(ServerInstance);
|
_servers.Add(ServerInstance);
|
||||||
Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_MONITORING_TEXT"].FormatExt(ServerInstance.Hostname.StripColors()));
|
|
||||||
_logger.LogInformation("Finishing initialization and now monitoring [{server}]", ServerInstance.Hostname, ServerInstance.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Logger.WriteVerbose(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_MONITORING_TEXT"].FormatExt(ServerInstance.Hostname));
|
||||||
// add the start event for this server
|
// add the start event for this server
|
||||||
|
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Start,
|
Type = GameEvent.EventType.Start,
|
||||||
@ -502,11 +507,13 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
catch (ServerException e)
|
catch (ServerException e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_UNFIXABLE"].FormatExt($"[{Conf.IPAddress}:{Conf.Port}]"));
|
Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_UNFIXABLE"].FormatExt($"[{Conf.IPAddress}:{Conf.Port}]"));
|
||||||
using (LogContext.PushProperty("Server", $"{Conf.IPAddress}:{Conf.Port}"))
|
|
||||||
|
if (e.GetType() == typeof(DvarException))
|
||||||
{
|
{
|
||||||
_logger.LogError(e, "Unexpected exception occurred during initialization");
|
Logger.WriteDebug($"{e.Message} {(e.GetType() == typeof(DvarException) ? $"({Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR_HELP"]})" : "")}");
|
||||||
}
|
}
|
||||||
|
|
||||||
lastException = e;
|
lastException = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,10 +548,20 @@ namespace IW4MAdmin.Application
|
|||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
public ILogger GetLogger(long serverId)
|
||||||
public ObsoleteLogger GetLogger(long serverId)
|
|
||||||
{
|
{
|
||||||
return _serviceProvider.GetRequiredService<ObsoleteLogger>();
|
if (_loggers.ContainsKey(serverId))
|
||||||
|
{
|
||||||
|
return _loggers[serverId];
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newLogger = new Logger($"IW4MAdmin-Server-{serverId}");
|
||||||
|
|
||||||
|
_loggers.Add(serverId, newLogger);
|
||||||
|
return newLogger;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<MessageToken> GetMessageTokens()
|
public IList<MessageToken> GetMessageTokens()
|
||||||
@ -590,7 +607,7 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public IRConParser GenerateDynamicRConParser(string name)
|
public IRConParser GenerateDynamicRConParser(string name)
|
||||||
{
|
{
|
||||||
return new DynamicRConParser(_serviceProvider.GetRequiredService<ILogger<BaseRConParser>>(), _parserRegexFactory)
|
return new DynamicRConParser(_parserRegexFactory)
|
||||||
{
|
{
|
||||||
Name = name
|
Name = name
|
||||||
};
|
};
|
||||||
|
@ -4,13 +4,24 @@ set TargetDir=%3
|
|||||||
set OutDir=%4
|
set OutDir=%4
|
||||||
set Version=%5
|
set Version=%5
|
||||||
|
|
||||||
|
echo %Version% > "%SolutionDir%DEPLOY\version.txt"
|
||||||
|
|
||||||
echo Copying dependency configs
|
echo Copying dependency configs
|
||||||
copy "%SolutionDir%WebfrontCore\%OutDir%*.deps.json" "%TargetDir%"
|
copy "%SolutionDir%WebfrontCore\%OutDir%*.deps.json" "%TargetDir%"
|
||||||
copy "%SolutionDir%SharedLibraryCore\%OutDir%*.deps.json" "%TargetDir%"
|
copy "%SolutionDir%SharedLibaryCore\%OutDir%*.deps.json" "%TargetDir%"
|
||||||
|
|
||||||
if not exist "%TargetDir%Plugins" (
|
if not exist "%TargetDir%Plugins" (
|
||||||
echo "Making plugin dir"
|
echo "Making plugin dir"
|
||||||
md "%TargetDir%Plugins"
|
md "%TargetDir%Plugins"
|
||||||
)
|
)
|
||||||
|
|
||||||
xcopy /y "%SolutionDir%Build\Plugins" "%TargetDir%Plugins\"
|
xcopy /y "%SolutionDir%Build\Plugins" "%TargetDir%Plugins\"
|
||||||
|
|
||||||
|
echo Copying plugins for publish
|
||||||
|
del %SolutionDir%BUILD\Plugins\Tests.dll
|
||||||
|
xcopy /Y "%SolutionDir%BUILD\Plugins" "%SolutionDir%Publish\Windows\Plugins\"
|
||||||
|
xcopy /Y "%SolutionDir%BUILD\Plugins" "%SolutionDir%Publish\WindowsPrerelease\Plugins\"
|
||||||
|
|
||||||
|
echo Copying script plugins for publish
|
||||||
|
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\Windows\Plugins\"
|
||||||
|
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\WindowsPrerelease\Plugins\"
|
@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"Serilog": {
|
|
||||||
"Using": [
|
|
||||||
"Serilog.Sinks.File"
|
|
||||||
],
|
|
||||||
"MinimumLevel": "Information",
|
|
||||||
"WriteTo": [
|
|
||||||
{
|
|
||||||
"Name": "File",
|
|
||||||
"Args": {
|
|
||||||
"path": "Log/IW4MAdmin-Application.log",
|
|
||||||
"rollingInterval": "Day",
|
|
||||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Server} {Level:u3}] {Message:lj}{NewLine}{Exception}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Enrich": [
|
|
||||||
"FromLogContext",
|
|
||||||
"WithMachineName",
|
|
||||||
"WithThreadId"
|
|
||||||
],
|
|
||||||
"Destructure": [
|
|
||||||
{
|
|
||||||
"Name": "ToMaximumDepth",
|
|
||||||
"Args": {
|
|
||||||
"maximumDestructuringDepth": 4
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "ToMaximumStringLength",
|
|
||||||
"Args": {
|
|
||||||
"maximumStringLength": 1000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "ToMaximumCollectionCount",
|
|
||||||
"Args": {
|
|
||||||
"maximumCollectionCount": 24
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,9 +5,7 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.EventParsers
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
{
|
{
|
||||||
@ -350,7 +348,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogError(e, $"Could not handle custom event generation");
|
_logger.WriteWarning($"Could not handle custom event generation - {e.GetExceptionInfo()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.EventParsers
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
{
|
{
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Serilog;
|
|
||||||
using SharedLibraryCore;
|
|
||||||
using SharedLibraryCore.Configuration;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Extensions
|
|
||||||
{
|
|
||||||
public static class StartupExtensions
|
|
||||||
{
|
|
||||||
private static ILogger _defaultLogger = null;
|
|
||||||
|
|
||||||
public static IServiceCollection AddBaseLogger(this IServiceCollection services,
|
|
||||||
ApplicationConfiguration appConfig)
|
|
||||||
{
|
|
||||||
if (_defaultLogger == null)
|
|
||||||
{
|
|
||||||
var configuration = new ConfigurationBuilder()
|
|
||||||
.AddJsonFile(Path.Join(Utilities.OperatingDirectory, "Configuration", "LoggingConfiguration.json"))
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
var loggerConfig = new LoggerConfiguration()
|
|
||||||
.ReadFrom.Configuration(configuration);
|
|
||||||
|
|
||||||
|
|
||||||
if (Utilities.IsDevelopment)
|
|
||||||
{
|
|
||||||
loggerConfig = loggerConfig.WriteTo.Console(
|
|
||||||
outputTemplate:"[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Server} {Level:u3}] {Message:lj}{NewLine}{Exception}")
|
|
||||||
.MinimumLevel.Debug();
|
|
||||||
}
|
|
||||||
|
|
||||||
_defaultLogger = loggerConfig.CreateLogger();
|
|
||||||
}
|
|
||||||
|
|
||||||
services.AddLogging(builder => builder.AddSerilog(_defaultLogger, dispose: true));
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,6 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Factories
|
namespace IW4MAdmin.Application.Factories
|
||||||
{
|
{
|
||||||
@ -20,12 +19,12 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
var baseUri = logUris[0];
|
var baseUri = logUris[0];
|
||||||
if (baseUri.Scheme == Uri.UriSchemeHttp)
|
if (baseUri.Scheme == Uri.UriSchemeHttp)
|
||||||
{
|
{
|
||||||
return new GameLogReaderHttp(logUris, eventParser, _serviceProvider.GetRequiredService<ILogger<GameLogReaderHttp>>());
|
return new GameLogReaderHttp(logUris, eventParser, _serviceProvider.GetRequiredService<ILogger>());
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (baseUri.Scheme == Uri.UriSchemeFile)
|
else if (baseUri.Scheme == Uri.UriSchemeFile)
|
||||||
{
|
{
|
||||||
return new GameLogReader(baseUri.LocalPath, eventParser, _serviceProvider.GetRequiredService<ILogger<GameLogReader>>());
|
return new GameLogReader(baseUri.LocalPath, eventParser, _serviceProvider.GetRequiredService<ILogger>());
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException($"No log reader implemented for Uri scheme \"{baseUri.Scheme}\"");
|
throw new NotImplementedException($"No log reader implemented for Uri scheme \"{baseUri.Scheme}\"");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore;
|
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Factories
|
namespace IW4MAdmin.Application.Factories
|
||||||
{
|
{
|
||||||
@ -11,21 +11,21 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
internal class GameServerInstanceFactory : IGameServerInstanceFactory
|
internal class GameServerInstanceFactory : IGameServerInstanceFactory
|
||||||
{
|
{
|
||||||
private readonly ITranslationLookup _translationLookup;
|
private readonly ITranslationLookup _translationLookup;
|
||||||
|
private readonly IRConConnectionFactory _rconConnectionFactory;
|
||||||
|
private readonly IGameLogReaderFactory _gameLogReaderFactory;
|
||||||
private readonly IMetaService _metaService;
|
private readonly IMetaService _metaService;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// base constructor
|
/// base constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="translationLookup"></param>
|
/// <param name="translationLookup"></param>
|
||||||
/// <param name="rconConnectionFactory"></param>
|
/// <param name="rconConnectionFactory"></param>
|
||||||
public GameServerInstanceFactory(ITranslationLookup translationLookup,
|
public GameServerInstanceFactory(ITranslationLookup translationLookup, IRConConnectionFactory rconConnectionFactory, IGameLogReaderFactory gameLogReaderFactory, IMetaService metaService)
|
||||||
IMetaService metaService,
|
|
||||||
IServiceProvider serviceProvider)
|
|
||||||
{
|
{
|
||||||
_translationLookup = translationLookup;
|
_translationLookup = translationLookup;
|
||||||
|
_rconConnectionFactory = rconConnectionFactory;
|
||||||
|
_gameLogReaderFactory = gameLogReaderFactory;
|
||||||
_metaService = metaService;
|
_metaService = metaService;
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -36,7 +36,7 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Server CreateServer(ServerConfiguration config, IManager manager)
|
public Server CreateServer(ServerConfiguration config, IManager manager)
|
||||||
{
|
{
|
||||||
return new IW4MServer(config, _translationLookup, _metaService, _serviceProvider);
|
return new IW4MServer(manager, config, _translationLookup, _rconConnectionFactory, _gameLogReaderFactory, _metaService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using IW4MAdmin.Application.RCon;
|
using IW4MAdmin.Application.RCon;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Factories
|
namespace IW4MAdmin.Application.Factories
|
||||||
{
|
{
|
||||||
@ -11,13 +10,13 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
internal class RConConnectionFactory : IRConConnectionFactory
|
internal class RConConnectionFactory : IRConConnectionFactory
|
||||||
{
|
{
|
||||||
private static readonly Encoding gameEncoding = Encoding.GetEncoding("windows-1252");
|
private static readonly Encoding gameEncoding = Encoding.GetEncoding("windows-1252");
|
||||||
private readonly ILogger<RConConnection> _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base constructor
|
/// Base constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger"></param>
|
/// <param name="logger"></param>
|
||||||
public RConConnectionFactory(ILogger<RConConnection> logger)
|
public RConConnectionFactory(ILogger logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,6 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Factories
|
namespace IW4MAdmin.Application.Factories
|
||||||
@ -17,20 +15,17 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ScriptCommandFactory : IScriptCommandFactory
|
public class ScriptCommandFactory : IScriptCommandFactory
|
||||||
{
|
{
|
||||||
private readonly CommandConfiguration _config;
|
private CommandConfiguration _config;
|
||||||
private readonly ITranslationLookup _transLookup;
|
private readonly ITranslationLookup _transLookup;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
|
|
||||||
public ScriptCommandFactory(CommandConfiguration config, ITranslationLookup transLookup, IServiceProvider serviceProvider)
|
public ScriptCommandFactory(CommandConfiguration config, ITranslationLookup transLookup)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_transLookup = transLookup;
|
_transLookup = transLookup;
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission,
|
public IManagerCommand CreateScriptCommand(string name, string alias, string description, string permission, bool isTargetRequired, IEnumerable<(string, bool)> args, Action<GameEvent> executeAction)
|
||||||
bool isTargetRequired, IEnumerable<(string, bool)> args, Action<GameEvent> executeAction)
|
|
||||||
{
|
{
|
||||||
var permissionEnum = Enum.Parse<Permission>(permission);
|
var permissionEnum = Enum.Parse<Permission>(permission);
|
||||||
var argsArray = args.Select(_arg => new CommandArgument
|
var argsArray = args.Select(_arg => new CommandArgument
|
||||||
@ -39,8 +34,7 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
Required = _arg.Item2
|
Required = _arg.Item2
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
return new ScriptCommand(name, alias, description, isTargetRequired, permissionEnum, argsArray, executeAction,
|
return new ScriptCommand(name, alias, description, isTargetRequired, permissionEnum, argsArray, executeAction, _config, _transLookup);
|
||||||
_config, _transLookup, _serviceProvider.GetRequiredService<ILogger<ScriptCommand>>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
using IW4MAdmin.Application.Misc;
|
using IW4MAdmin.Application.Misc;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Events;
|
using SharedLibraryCore.Events;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
{
|
{
|
||||||
public class GameEventHandler : IEventHandler
|
public class GameEventHandler : IEventHandler
|
||||||
{
|
{
|
||||||
private readonly EventLog _eventLog;
|
private readonly EventLog _eventLog;
|
||||||
private readonly ILogger _logger;
|
|
||||||
private static readonly GameEvent.EventType[] overrideEvents = new[]
|
private static readonly GameEvent.EventType[] overrideEvents = new[]
|
||||||
{
|
{
|
||||||
GameEvent.EventType.Connect,
|
GameEvent.EventType.Connect,
|
||||||
@ -21,23 +22,34 @@ namespace IW4MAdmin.Application
|
|||||||
GameEvent.EventType.Stop
|
GameEvent.EventType.Stop
|
||||||
};
|
};
|
||||||
|
|
||||||
public GameEventHandler(ILogger<GameEventHandler> logger)
|
public GameEventHandler()
|
||||||
{
|
{
|
||||||
_eventLog = new EventLog();
|
_eventLog = new EventLog();
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleEvent(IManager manager, GameEvent gameEvent)
|
public void HandleEvent(IManager manager, GameEvent gameEvent)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
ThreadPool.GetMaxThreads(out int workerThreads, out int n);
|
||||||
|
ThreadPool.GetAvailableThreads(out int availableThreads, out int m);
|
||||||
|
gameEvent.Owner.Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
||||||
|
|
||||||
|
#endif
|
||||||
if (manager.IsRunning || overrideEvents.Contains(gameEvent.Type))
|
if (manager.IsRunning || overrideEvents.Contains(gameEvent.Type))
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
gameEvent.Owner.Logger.WriteDebug($"Adding event with id {gameEvent.Id}");
|
||||||
|
#endif
|
||||||
|
|
||||||
EventApi.OnGameEvent(gameEvent);
|
EventApi.OnGameEvent(gameEvent);
|
||||||
Task.Factory.StartNew(() => manager.ExecuteEvent(gameEvent));
|
Task.Factory.StartNew(() => manager.ExecuteEvent(gameEvent));
|
||||||
}
|
}
|
||||||
|
#if DEBUG
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Skipping event as we're shutting down {eventId}", gameEvent.Id);
|
gameEvent.Owner.Logger.WriteDebug($"Skipping event as we're shutting down {gameEvent.Id}");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,6 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.IO
|
namespace IW4MAdmin.Application.IO
|
||||||
{
|
{
|
||||||
@ -15,14 +12,12 @@ namespace IW4MAdmin.Application.IO
|
|||||||
private readonly Server _server;
|
private readonly Server _server;
|
||||||
private readonly IGameLogReader _reader;
|
private readonly IGameLogReader _reader;
|
||||||
private readonly bool _ignoreBots;
|
private readonly bool _ignoreBots;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public GameLogEventDetection(ILogger<GameLogEventDetection> logger, IW4MServer server, Uri[] gameLogUris, IGameLogReaderFactory gameLogReaderFactory)
|
public GameLogEventDetection(Server server, Uri[] gameLogUris, IGameLogReaderFactory gameLogReaderFactory)
|
||||||
{
|
{
|
||||||
_reader = gameLogReaderFactory.CreateGameLogReader(gameLogUris, server.EventParser);
|
_reader = gameLogReaderFactory.CreateGameLogReader(gameLogUris, server.EventParser);
|
||||||
_server = server;
|
_server = server;
|
||||||
_ignoreBots = server?.Manager.GetApplicationSettings().Configuration().IgnoreBots ?? false;
|
_ignoreBots = server?.Manager.GetApplicationSettings().Configuration().IgnoreBots ?? false;
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PollForChanges()
|
public async Task PollForChanges()
|
||||||
@ -38,17 +33,15 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
using(LogContext.PushProperty("Server", _server.ToString()))
|
_server.Logger.WriteWarning($"Failed to update log event for {_server.EndPoint}");
|
||||||
{
|
_server.Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
_logger.LogError(e, "Failed to update log event for {endpoint}", _server.EndPoint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(_reader.UpdateInterval, _server.Manager.CancellationToken);
|
await Task.Delay(_reader.UpdateInterval, _server.Manager.CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug("Stopped polling for changes");
|
_server.Logger.WriteDebug("Stopped polling for changes");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateLogEvents()
|
public async Task UpdateLogEvents()
|
||||||
@ -75,6 +68,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
_server.Logger.WriteVerbose(gameEvent.Data);
|
||||||
|
#endif
|
||||||
gameEvent.Owner = _server;
|
gameEvent.Owner = _server;
|
||||||
|
|
||||||
// we don't want to add the event if ignoreBots is on and the event comes from a bot
|
// we don't want to add the event if ignoreBots is on and the event comes from a bot
|
||||||
@ -106,14 +102,10 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
{
|
{
|
||||||
if (_ignoreBots)
|
if (!_ignoreBots)
|
||||||
{
|
{
|
||||||
continue;
|
_server.Logger.WriteWarning("Could not find client in client list when parsing event line");
|
||||||
}
|
_server.Logger.WriteDebug(gameEvent.Data);
|
||||||
|
|
||||||
using(LogContext.PushProperty("Server", _server.ToString()))
|
|
||||||
{
|
|
||||||
_logger.LogError("Could not find client in client list when parsing event line {data}", gameEvent.Data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,6 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.IO
|
namespace IW4MAdmin.Application.IO
|
||||||
{
|
{
|
||||||
@ -21,7 +19,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
public int UpdateInterval => 300;
|
public int UpdateInterval => 300;
|
||||||
|
|
||||||
public GameLogReader(string logFile, IEventParser parser, ILogger<GameLogReader> logger)
|
public GameLogReader(string logFile, IEventParser parser, ILogger logger)
|
||||||
{
|
{
|
||||||
_logFile = logFile;
|
_logFile = logFile;
|
||||||
_parser = parser;
|
_parser = parser;
|
||||||
@ -75,7 +73,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogError(e, "Could not properly parse event line {@eventLine}", eventLine);
|
_logger.WriteWarning("Could not properly parse event line");
|
||||||
|
_logger.WriteDebug(e.Message);
|
||||||
|
_logger.WriteDebug(eventLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,8 +6,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.IO
|
namespace IW4MAdmin.Application.IO
|
||||||
{
|
{
|
||||||
@ -22,7 +20,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
private readonly string _safeLogPath;
|
private readonly string _safeLogPath;
|
||||||
private string lastKey = "next";
|
private string lastKey = "next";
|
||||||
|
|
||||||
public GameLogReaderHttp(Uri[] gameLogServerUris, IEventParser parser, ILogger<GameLogReaderHttp> logger)
|
public GameLogReaderHttp(Uri[] gameLogServerUris, IEventParser parser, ILogger logger)
|
||||||
{
|
{
|
||||||
_eventParser = parser;
|
_eventParser = parser;
|
||||||
_logServerApi = RestClient.For<IGameLogServer>(gameLogServerUris[0].ToString());
|
_logServerApi = RestClient.For<IGameLogServer>(gameLogServerUris[0].ToString());
|
||||||
@ -42,7 +40,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
if (!response.Success && string.IsNullOrEmpty(lastKey))
|
if (!response.Success && string.IsNullOrEmpty(lastKey))
|
||||||
{
|
{
|
||||||
_logger.LogError("Could not get log server info of {logPath}", _safeLogPath);
|
_logger.WriteError($"Could not get log server info of {_safeLogPath}");
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +62,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogError(e, "Could not properly parse event line from http {eventLine}", eventLine);
|
_logger.WriteError("Could not properly parse event line from http");
|
||||||
|
_logger.WriteDebug(e.Message);
|
||||||
|
_logger.WriteDebug(eventLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -6,22 +6,15 @@ using System.Collections.Generic;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SharedLibraryCore.Configuration;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Localization
|
namespace IW4MAdmin.Application.Localization
|
||||||
{
|
{
|
||||||
public static class Configure
|
public class Configure
|
||||||
{
|
{
|
||||||
public static ITranslationLookup Initialize(ILogger logger, IMasterApi apiInstance, ApplicationConfiguration applicationConfiguration)
|
public static ITranslationLookup Initialize(bool useLocalTranslation, IMasterApi apiInstance, string customLocale = null)
|
||||||
{
|
{
|
||||||
var useLocalTranslation = applicationConfiguration?.UseLocalTranslations ?? true;
|
string currentLocale = string.IsNullOrEmpty(customLocale) ? CultureInfo.CurrentCulture.Name : customLocale;
|
||||||
var customLocale = applicationConfiguration?.EnableCustomLocale ?? false
|
string[] localizationFiles = Directory.GetFiles(Path.Join(Utilities.OperatingDirectory, "Localization"), $"*.{currentLocale}.json");
|
||||||
? (applicationConfiguration.CustomLocale ?? "en-US")
|
|
||||||
: "en-US";
|
|
||||||
var currentLocale = string.IsNullOrEmpty(customLocale) ? CultureInfo.CurrentCulture.Name : customLocale;
|
|
||||||
var localizationFiles = Directory.GetFiles(Path.Join(Utilities.OperatingDirectory, "Localization"), $"*.{currentLocale}.json");
|
|
||||||
|
|
||||||
if (!useLocalTranslation)
|
if (!useLocalTranslation)
|
||||||
{
|
{
|
||||||
@ -32,10 +25,9 @@ namespace IW4MAdmin.Application.Localization
|
|||||||
return localization.LocalizationIndex;
|
return localization.LocalizationIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
// the online localization failed so will default to local files
|
// the online localization failed so will default to local files
|
||||||
logger.LogWarning(ex, "Could not download latest translations");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,11 +60,13 @@ namespace IW4MAdmin.Application.Localization
|
|||||||
{
|
{
|
||||||
if (!localizationDict.TryAdd(item.Key, item.Value))
|
if (!localizationDict.TryAdd(item.Key, item.Value))
|
||||||
{
|
{
|
||||||
logger.LogError("Could not add locale string {key} to localization", item.Key);
|
Program.ServerManager.GetLogger(0).WriteError($"Could not add locale string {item.Key} to localization");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string localizationFile = $"{Path.Join(Utilities.OperatingDirectory, "Localization")}{Path.DirectorySeparatorChar}IW4MAdmin.{currentLocale}-{currentLocale.ToUpper()}.json";
|
||||||
|
|
||||||
Utilities.CurrentLocalization = new SharedLibraryCore.Localization.Layout(localizationDict)
|
Utilities.CurrentLocalization = new SharedLibraryCore.Localization.Layout(localizationDict)
|
||||||
{
|
{
|
||||||
LocalizationName = currentLocale,
|
LocalizationName = currentLocale,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using IW4MAdmin.Application.API.Master;
|
using IW4MAdmin.Application.API.Master;
|
||||||
using IW4MAdmin.Application.EventParsers;
|
using IW4MAdmin.Application.EventParsers;
|
||||||
using IW4MAdmin.Application.Factories;
|
using IW4MAdmin.Application.Factories;
|
||||||
|
using IW4MAdmin.Application.Helpers;
|
||||||
using IW4MAdmin.Application.Meta;
|
using IW4MAdmin.Application.Meta;
|
||||||
using IW4MAdmin.Application.Migration;
|
using IW4MAdmin.Application.Migration;
|
||||||
using IW4MAdmin.Application.Misc;
|
using IW4MAdmin.Application.Misc;
|
||||||
@ -23,10 +24,6 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IW4MAdmin.Application.Extensions;
|
|
||||||
using IW4MAdmin.Application.Localization;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
{
|
{
|
||||||
@ -79,32 +76,29 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
restart:
|
restart:
|
||||||
ITranslationLookup translationLookup = null;
|
ITranslationLookup translationLookup = null;
|
||||||
var logger = BuildDefaultLogger<Program>(new ApplicationConfiguration());
|
|
||||||
Utilities.DefaultLogger = logger;
|
|
||||||
logger.LogInformation("Begin IW4MAdmin startup. Version is {version} {@args}", Version, args);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// do any needed housekeeping file/folder migrations
|
// do any needed housekeeping file/folder migrations
|
||||||
ConfigurationMigration.MoveConfigFolder10518(null);
|
ConfigurationMigration.MoveConfigFolder10518(null);
|
||||||
ConfigurationMigration.CheckDirectories();
|
ConfigurationMigration.CheckDirectories();
|
||||||
logger.LogDebug("Configuring services...");
|
|
||||||
var services = ConfigureServices(args);
|
var services = ConfigureServices(args);
|
||||||
serviceProvider = services.BuildServiceProvider();
|
serviceProvider = services.BuildServiceProvider();
|
||||||
var versionChecker = serviceProvider.GetRequiredService<IMasterCommunication>();
|
var versionChecker = serviceProvider.GetRequiredService<IMasterCommunication>();
|
||||||
ServerManager = (ApplicationManager)serviceProvider.GetRequiredService<IManager>();
|
ServerManager = (ApplicationManager)serviceProvider.GetRequiredService<IManager>();
|
||||||
translationLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
translationLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
||||||
|
|
||||||
|
ServerManager.Logger.WriteInfo(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_VERSION"].FormatExt(Version));
|
||||||
|
|
||||||
await versionChecker.CheckVersion();
|
await versionChecker.CheckVersion();
|
||||||
await ServerManager.Init();
|
await ServerManager.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
string failMessage = translationLookup == null ? "Failed to initialize IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"];
|
string failMessage = translationLookup == null ? "Failed to initalize IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"];
|
||||||
string exitMessage = translationLookup == null ? "Press enter to exit..." : translationLookup["MANAGER_EXIT"];
|
string exitMessage = translationLookup == null ? "Press enter to exit..." : translationLookup["MANAGER_EXIT"];
|
||||||
|
|
||||||
logger.LogCritical(e, "Failed to initialize IW4MAdmin");
|
|
||||||
Console.WriteLine(failMessage);
|
Console.WriteLine(failMessage);
|
||||||
|
|
||||||
while (e.InnerException != null)
|
while (e.InnerException != null)
|
||||||
@ -137,14 +131,13 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ApplicationTask = RunApplicationTasksAsync(logger);
|
ApplicationTask = RunApplicationTasksAsync();
|
||||||
await ApplicationTask;
|
await ApplicationTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.LogCritical(e, "Failed to launch IW4MAdmin");
|
string failMessage = translationLookup == null ? "Failed to initalize IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"];
|
||||||
string failMessage = translationLookup == null ? "Failed to launch IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"];
|
|
||||||
Console.WriteLine($"{failMessage}: {e.GetExceptionInfo()}");
|
Console.WriteLine($"{failMessage}: {e.GetExceptionInfo()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +153,7 @@ namespace IW4MAdmin.Application
|
|||||||
/// runs the core application tasks
|
/// runs the core application tasks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static async Task RunApplicationTasksAsync(ILogger logger)
|
private static async Task RunApplicationTasksAsync()
|
||||||
{
|
{
|
||||||
var webfrontTask = ServerManager.GetApplicationSettings().Configuration().EnableWebFront ?
|
var webfrontTask = ServerManager.GetApplicationSettings().Configuration().EnableWebFront ?
|
||||||
WebfrontCore.Program.Init(ServerManager, serviceProvider, ServerManager.CancellationToken) :
|
WebfrontCore.Program.Init(ServerManager, serviceProvider, ServerManager.CancellationToken) :
|
||||||
@ -168,7 +161,7 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
// we want to run this one on a manual thread instead of letting the thread pool handle it,
|
// we want to run this one on a manual thread instead of letting the thread pool handle it,
|
||||||
// because we can't exit early from waiting on console input, and it prevents us from restarting
|
// because we can't exit early from waiting on console input, and it prevents us from restarting
|
||||||
var inputThread = new Thread(async () => await ReadConsoleInput(logger));
|
var inputThread = new Thread(async () => await ReadConsoleInput());
|
||||||
inputThread.Start();
|
inputThread.Start();
|
||||||
|
|
||||||
var tasks = new[]
|
var tasks = new[]
|
||||||
@ -178,11 +171,9 @@ namespace IW4MAdmin.Application
|
|||||||
serviceProvider.GetRequiredService<IMasterCommunication>().RunUploadStatus(ServerManager.CancellationToken)
|
serviceProvider.GetRequiredService<IMasterCommunication>().RunUploadStatus(ServerManager.CancellationToken)
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.LogDebug("Starting webfront and input tasks");
|
|
||||||
await Task.WhenAll(tasks);
|
await Task.WhenAll(tasks);
|
||||||
|
|
||||||
logger.LogInformation("Shutdown completed successfully");
|
ServerManager.Logger.WriteVerbose(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_SHUTDOWN_SUCCESS"]);
|
||||||
Console.Write(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_SHUTDOWN_SUCCESS"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -190,11 +181,11 @@ namespace IW4MAdmin.Application
|
|||||||
/// reads input from the console and executes entered commands on the default server
|
/// reads input from the console and executes entered commands on the default server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static async Task ReadConsoleInput(ILogger logger)
|
private static async Task ReadConsoleInput()
|
||||||
{
|
{
|
||||||
if (Console.IsInputRedirected)
|
if (Console.IsInputRedirected)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Disabling console input as it has been redirected");
|
ServerManager.Logger.WriteInfo("Disabling console input as it has been redirected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,29 +221,68 @@ namespace IW4MAdmin.Application
|
|||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection HandlePluginRegistration(ApplicationConfiguration appConfig,
|
/// <summary>
|
||||||
IServiceCollection serviceCollection,
|
/// Configures the dependency injection services
|
||||||
IMasterApi masterApi)
|
/// </summary>
|
||||||
|
private static IServiceCollection ConfigureServices(string[] args)
|
||||||
{
|
{
|
||||||
var defaultLogger = BuildDefaultLogger<Program>(appConfig);
|
var defaultLogger = new Logger("IW4MAdmin-Manager");
|
||||||
var pluginServiceProvider = new ServiceCollection()
|
var pluginImporter = new PluginImporter(defaultLogger);
|
||||||
.AddBaseLogger(appConfig)
|
|
||||||
.AddSingleton(appConfig)
|
var serviceCollection = new ServiceCollection();
|
||||||
.AddSingleton(masterApi)
|
serviceCollection.AddSingleton<IServiceCollection>(_serviceProvider => serviceCollection)
|
||||||
.AddSingleton<IRemoteAssemblyHandler, RemoteAssemblyHandler>()
|
.AddSingleton(new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings") as IConfigurationHandler<ApplicationConfiguration>)
|
||||||
.AddSingleton<IPluginImporter, PluginImporter>()
|
.AddSingleton(new BaseConfigurationHandler<CommandConfiguration>("CommandConfiguration") as IConfigurationHandler<CommandConfiguration>)
|
||||||
.BuildServiceProvider();
|
.AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService<IConfigurationHandler<ApplicationConfiguration>>().Configuration() ?? new ApplicationConfiguration())
|
||||||
|
.AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService<IConfigurationHandler<CommandConfiguration>>().Configuration() ?? new CommandConfiguration())
|
||||||
|
.AddSingleton<ILogger>(_serviceProvider => defaultLogger)
|
||||||
|
.AddSingleton<IPluginImporter, PluginImporter>()
|
||||||
|
.AddSingleton<IMiddlewareActionHandler, MiddlewareActionHandler>()
|
||||||
|
.AddSingleton<IRConConnectionFactory, RConConnectionFactory>()
|
||||||
|
.AddSingleton<IGameServerInstanceFactory, GameServerInstanceFactory>()
|
||||||
|
.AddSingleton<IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
|
||||||
|
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
||||||
|
.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>()
|
||||||
|
.AddSingleton<IGameLogReaderFactory, GameLogReaderFactory>()
|
||||||
|
.AddSingleton<IScriptCommandFactory, ScriptCommandFactory>()
|
||||||
|
.AddSingleton<IAuditInformationRepository, AuditInformationRepository>()
|
||||||
|
.AddSingleton<IEntityService<EFClient>, ClientService>()
|
||||||
|
.AddSingleton<IMetaService, MetaService>()
|
||||||
|
.AddSingleton<IMetaRegistration, MetaRegistration>()
|
||||||
|
.AddSingleton<IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
|
||||||
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
|
||||||
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
|
||||||
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
|
||||||
|
.AddSingleton<IResourceQueryHelper<ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>()
|
||||||
|
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
||||||
|
.AddSingleton(_serviceProvider =>
|
||||||
|
{
|
||||||
|
var config = _serviceProvider.GetRequiredService<IConfigurationHandler<ApplicationConfiguration>>().Configuration();
|
||||||
|
return Localization.Configure.Initialize(useLocalTranslation: config?.UseLocalTranslations ?? false,
|
||||||
|
apiInstance: _serviceProvider.GetRequiredService<IMasterApi>(),
|
||||||
|
customLocale: config?.EnableCustomLocale ?? false ? (config.CustomLocale ?? "en-US") : "en-US");
|
||||||
|
})
|
||||||
|
.AddSingleton<IManager, ApplicationManager>()
|
||||||
|
.AddSingleton(_serviceProvider => RestClient
|
||||||
|
.For<IMasterApi>(Utilities.IsDevelopment ? new Uri("http://127.0.0.1:8080") : _serviceProvider
|
||||||
|
.GetRequiredService<IConfigurationHandler<ApplicationConfiguration>>().Configuration()?.MasterUrl ??
|
||||||
|
new ApplicationConfiguration().MasterUrl))
|
||||||
|
.AddSingleton<IMasterCommunication, MasterCommunication>();
|
||||||
|
|
||||||
|
if (args.Contains("serialevents"))
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<IEventHandler, SerialGameEventHandler>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<IEventHandler, GameEventHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
var pluginImporter = pluginServiceProvider.GetRequiredService<IPluginImporter>();
|
|
||||||
|
|
||||||
// we need to register the rest client with regular collection
|
|
||||||
serviceCollection.AddSingleton(masterApi);
|
|
||||||
|
|
||||||
// register the native commands
|
// register the native commands
|
||||||
foreach (var commandType in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes()
|
foreach (var commandType in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes()
|
||||||
.Where(_command => _command.BaseType == typeof(Command)))
|
.Where(_command => _command.BaseType == typeof(Command)))
|
||||||
{
|
{
|
||||||
defaultLogger.LogDebug("Registered native command type {name}", commandType.Name);
|
defaultLogger.WriteInfo($"Registered native command type {commandType.Name}");
|
||||||
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,14 +290,14 @@ namespace IW4MAdmin.Application
|
|||||||
var pluginImplementations = pluginImporter.DiscoverAssemblyPluginImplementations();
|
var pluginImplementations = pluginImporter.DiscoverAssemblyPluginImplementations();
|
||||||
foreach (var pluginType in pluginImplementations.Item1)
|
foreach (var pluginType in pluginImplementations.Item1)
|
||||||
{
|
{
|
||||||
defaultLogger.LogDebug("Registered plugin type {name}", pluginType.FullName);
|
defaultLogger.WriteInfo($"Registered plugin type {pluginType.FullName}");
|
||||||
serviceCollection.AddSingleton(typeof(IPlugin), pluginType);
|
serviceCollection.AddSingleton(typeof(IPlugin), pluginType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the plugin commands
|
// register the plugin commands
|
||||||
foreach (var commandType in pluginImplementations.Item2)
|
foreach (var commandType in pluginImplementations.Item2)
|
||||||
{
|
{
|
||||||
defaultLogger.LogDebug("Registered plugin command type {name}", commandType.FullName);
|
defaultLogger.WriteInfo($"Registered plugin command type {commandType.FullName}");
|
||||||
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,86 +321,5 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
return serviceCollection;
|
return serviceCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configures the dependency injection services
|
|
||||||
/// </summary>
|
|
||||||
private static IServiceCollection ConfigureServices(string[] args)
|
|
||||||
{
|
|
||||||
// setup the static resources (config/master api/translations)
|
|
||||||
var serviceCollection = new ServiceCollection();
|
|
||||||
var appConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
|
|
||||||
var appConfig = appConfigHandler.Configuration();
|
|
||||||
var masterUri = Utilities.IsDevelopment
|
|
||||||
? new Uri("http://127.0.0.1:8080")
|
|
||||||
: appConfig?.MasterUrl ?? new ApplicationConfiguration().MasterUrl;
|
|
||||||
var masterRestClient = RestClient.For<IMasterApi>(masterUri);
|
|
||||||
var translationLookup = Configure.Initialize(Utilities.DefaultLogger, masterRestClient, appConfig);
|
|
||||||
|
|
||||||
if (appConfig == null)
|
|
||||||
{
|
|
||||||
appConfig = (ApplicationConfiguration) new ApplicationConfiguration().Generate();
|
|
||||||
appConfigHandler.Set(appConfig);
|
|
||||||
appConfigHandler.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
// build the dependency list
|
|
||||||
HandlePluginRegistration(appConfig, serviceCollection, masterRestClient);
|
|
||||||
|
|
||||||
serviceCollection
|
|
||||||
.AddBaseLogger(appConfig)
|
|
||||||
.AddSingleton<IServiceCollection>(_serviceProvider => serviceCollection)
|
|
||||||
.AddSingleton((IConfigurationHandler<ApplicationConfiguration>) appConfigHandler)
|
|
||||||
.AddSingleton(new BaseConfigurationHandler<CommandConfiguration>("CommandConfiguration") as IConfigurationHandler<CommandConfiguration>)
|
|
||||||
.AddSingleton(appConfig)
|
|
||||||
.AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService<IConfigurationHandler<CommandConfiguration>>().Configuration() ?? new CommandConfiguration())
|
|
||||||
.AddSingleton<IPluginImporter, PluginImporter>()
|
|
||||||
.AddSingleton<IMiddlewareActionHandler, MiddlewareActionHandler>()
|
|
||||||
.AddSingleton<IRConConnectionFactory, RConConnectionFactory>()
|
|
||||||
.AddSingleton<IGameServerInstanceFactory, GameServerInstanceFactory>()
|
|
||||||
.AddSingleton<IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
|
|
||||||
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
|
||||||
.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>()
|
|
||||||
.AddSingleton<IGameLogReaderFactory, GameLogReaderFactory>()
|
|
||||||
.AddSingleton<IScriptCommandFactory, ScriptCommandFactory>()
|
|
||||||
.AddSingleton<IAuditInformationRepository, AuditInformationRepository>()
|
|
||||||
.AddSingleton<IEntityService<EFClient>, ClientService>()
|
|
||||||
.AddSingleton<IMetaService, MetaService>()
|
|
||||||
.AddSingleton<ClientService>()
|
|
||||||
.AddSingleton<ChangeHistoryService>()
|
|
||||||
.AddSingleton<IMetaRegistration, MetaRegistration>()
|
|
||||||
.AddSingleton<IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
|
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
|
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
|
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
|
|
||||||
.AddSingleton<IResourceQueryHelper<ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>()
|
|
||||||
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
|
||||||
.AddSingleton<IRemoteAssemblyHandler, RemoteAssemblyHandler>()
|
|
||||||
.AddSingleton<IMasterCommunication, MasterCommunication>()
|
|
||||||
.AddSingleton<IManager, ApplicationManager>()
|
|
||||||
.AddSingleton<SharedLibraryCore.Interfaces.ILogger, Logger>()
|
|
||||||
.AddSingleton(translationLookup);
|
|
||||||
|
|
||||||
if (args.Contains("serialevents"))
|
|
||||||
{
|
|
||||||
serviceCollection.AddSingleton<IEventHandler, SerialGameEventHandler>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
serviceCollection.AddSingleton<IEventHandler, GameEventHandler>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return serviceCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ILogger BuildDefaultLogger<T>(ApplicationConfiguration appConfig)
|
|
||||||
{
|
|
||||||
var collection = new ServiceCollection()
|
|
||||||
.AddBaseLogger(appConfig)
|
|
||||||
.BuildServiceProvider();
|
|
||||||
|
|
||||||
return collection.GetRequiredService<ILogger<T>>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Dtos.Meta.Responses;
|
using SharedLibraryCore.Dtos.Meta.Responses;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.QueryHelper;
|
using SharedLibraryCore.QueryHelper;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Meta
|
namespace IW4MAdmin.Application.Meta
|
||||||
{
|
{
|
||||||
@ -20,7 +18,7 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
|
|
||||||
public AdministeredPenaltyResourceQueryHelper(ILogger<AdministeredPenaltyResourceQueryHelper> logger, IDatabaseContextFactory contextFactory)
|
public AdministeredPenaltyResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory)
|
||||||
{
|
{
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -6,8 +6,6 @@ using SharedLibraryCore.QueryHelper;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Meta
|
namespace IW4MAdmin.Application.Meta
|
||||||
{
|
{
|
||||||
@ -21,7 +19,7 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
private readonly IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse> _administeredPenaltyHelper;
|
private readonly IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse> _administeredPenaltyHelper;
|
||||||
private readonly IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse> _updatedAliasHelper;
|
private readonly IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse> _updatedAliasHelper;
|
||||||
|
|
||||||
public MetaRegistration(ILogger<MetaRegistration> logger, IMetaService metaService, ITranslationLookup transLookup, IEntityService<EFClient> clientEntityService,
|
public MetaRegistration(ILogger logger, IMetaService metaService, ITranslationLookup transLookup, IEntityService<EFClient> clientEntityService,
|
||||||
IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse> receivedPenaltyHelper,
|
IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse> receivedPenaltyHelper,
|
||||||
IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse> administeredPenaltyHelper,
|
IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse> administeredPenaltyHelper,
|
||||||
IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse> updatedAliasHelper)
|
IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse> updatedAliasHelper)
|
||||||
@ -84,7 +82,7 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
|
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("No client found with id {clientId} when generating profile meta", request.ClientId);
|
_logger.WriteWarning($"No client found with id {request.ClientId} when generating profile meta");
|
||||||
return metaList;
|
return metaList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,12 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Dtos.Meta.Responses;
|
using SharedLibraryCore.Dtos.Meta.Responses;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.QueryHelper;
|
using SharedLibraryCore.QueryHelper;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Meta
|
namespace IW4MAdmin.Application.Meta
|
||||||
{
|
{
|
||||||
@ -22,7 +20,7 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
|
|
||||||
public ReceivedPenaltyResourceQueryHelper(ILogger<ReceivedPenaltyResourceQueryHelper> logger, IDatabaseContextFactory contextFactory)
|
public ReceivedPenaltyResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory)
|
||||||
{
|
{
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -6,8 +6,6 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using SharedLibraryCore.QueryHelper;
|
using SharedLibraryCore.QueryHelper;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Meta
|
namespace IW4MAdmin.Application.Meta
|
||||||
{
|
{
|
||||||
@ -20,7 +18,7 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
|
|
||||||
public UpdatedAliasResourceQueryHelper(ILogger<UpdatedAliasResourceQueryHelper> logger, IDatabaseContextFactory contextFactory)
|
public UpdatedAliasResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Migration
|
namespace IW4MAdmin.Application.Migration
|
||||||
{
|
{
|
||||||
@ -53,6 +56,7 @@ namespace IW4MAdmin.Application.Migration
|
|||||||
|
|
||||||
if (!Directory.Exists(configDirectory))
|
if (!Directory.Exists(configDirectory))
|
||||||
{
|
{
|
||||||
|
log?.WriteDebug($"Creating directory for configs {configDirectory}");
|
||||||
Directory.CreateDirectory(configDirectory);
|
Directory.CreateDirectory(configDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +66,7 @@ namespace IW4MAdmin.Application.Migration
|
|||||||
|
|
||||||
foreach (var configFile in configurationFiles)
|
foreach (var configFile in configurationFiles)
|
||||||
{
|
{
|
||||||
|
log?.WriteDebug($"Moving config file {configFile}");
|
||||||
string destinationPath = Path.Join("Configuration", configFile);
|
string destinationPath = Path.Join("Configuration", configFile);
|
||||||
if (!File.Exists(destinationPath))
|
if (!File.Exists(destinationPath))
|
||||||
{
|
{
|
||||||
@ -72,6 +77,7 @@ namespace IW4MAdmin.Application.Migration
|
|||||||
if (!File.Exists(Path.Join("Database", "Database.db")) &&
|
if (!File.Exists(Path.Join("Database", "Database.db")) &&
|
||||||
File.Exists("Database.db"))
|
File.Exists("Database.db"))
|
||||||
{
|
{
|
||||||
|
log?.WriteDebug("Moving database file");
|
||||||
File.Move("Database.db", Path.Join("Database", "Database.db"));
|
File.Move("Database.db", Path.Join("Database", "Database.db"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
63
Application/Misc/EventProfiler.cs
Normal file
63
Application/Misc/EventProfiler.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
internal class EventPerformance
|
||||||
|
{
|
||||||
|
public long ExecutionTime { get; set; }
|
||||||
|
public GameEvent Event { get; set; }
|
||||||
|
public string EventInfo => $"{Event.Type}, {Event.FailReason}, {Event.IsBlocking}, {Event.Data}, {Event.Message}, {Event.Extra}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DuplicateKeyComparer<TKey> : IComparer<TKey> where TKey : IComparable
|
||||||
|
{
|
||||||
|
public int Compare(TKey x, TKey y)
|
||||||
|
{
|
||||||
|
int result = x.CompareTo(y);
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class EventProfiler
|
||||||
|
{
|
||||||
|
public double AverageEventTime { get; private set; }
|
||||||
|
public double MaxEventTime => Events.Values.Last().ExecutionTime;
|
||||||
|
public double MinEventTime => Events.Values[0].ExecutionTime;
|
||||||
|
public int TotalEventCount => Events.Count;
|
||||||
|
public SortedList<long, EventPerformance> Events { get; private set; } = new SortedList<long, EventPerformance>(new DuplicateKeyComparer<long>());
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public EventProfiler(ILogger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Profile(DateTime start, DateTime end, GameEvent gameEvent)
|
||||||
|
{
|
||||||
|
_logger.WriteDebug($"Starting profile of event {gameEvent.Id}");
|
||||||
|
long executionTime = (long)Math.Round((end - start).TotalMilliseconds);
|
||||||
|
|
||||||
|
var perf = new EventPerformance()
|
||||||
|
{
|
||||||
|
Event = gameEvent,
|
||||||
|
ExecutionTime = executionTime
|
||||||
|
};
|
||||||
|
|
||||||
|
lock (Events)
|
||||||
|
{
|
||||||
|
Events.Add(executionTime, perf);
|
||||||
|
}
|
||||||
|
|
||||||
|
AverageEventTime = (AverageEventTime * (TotalEventCount - 1) + executionTime) / TotalEventCount;
|
||||||
|
_logger.WriteDebug($"Finished profile of event {gameEvent.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +1,132 @@
|
|||||||
using System;
|
using IW4MAdmin.Application.IO;
|
||||||
using Microsoft.Extensions.Logging;
|
using SharedLibraryCore;
|
||||||
using ILogger = SharedLibraryCore.Interfaces.ILogger;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
{
|
{
|
||||||
[Obsolete]
|
|
||||||
public class Logger : ILogger
|
public class Logger : ILogger
|
||||||
{
|
{
|
||||||
private readonly Microsoft.Extensions.Logging.ILogger _logger;
|
enum LogType
|
||||||
|
|
||||||
public Logger(ILogger<Logger> logger)
|
|
||||||
{
|
{
|
||||||
_logger = logger;
|
Verbose,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Assert
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly string FileName;
|
||||||
|
readonly ReaderWriterLockSlim WritingLock;
|
||||||
|
static readonly short MAX_LOG_FILES = 10;
|
||||||
|
|
||||||
|
public Logger(string fn)
|
||||||
|
{
|
||||||
|
FileName = Path.Join(Utilities.OperatingDirectory, "Log", $"{fn}.log");
|
||||||
|
WritingLock = new ReaderWriterLockSlim();
|
||||||
|
RotateLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Logger()
|
||||||
|
{
|
||||||
|
WritingLock.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// rotates logs when log is initialized
|
||||||
|
/// </summary>
|
||||||
|
private void RotateLogs()
|
||||||
|
{
|
||||||
|
string maxLog = FileName + MAX_LOG_FILES;
|
||||||
|
|
||||||
|
if (File.Exists(maxLog))
|
||||||
|
{
|
||||||
|
File.Delete(maxLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = MAX_LOG_FILES - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
string logToMove = i == 0 ? FileName : FileName + i;
|
||||||
|
string movedLogName = FileName + (i + 1);
|
||||||
|
|
||||||
|
if (File.Exists(logToMove))
|
||||||
|
{
|
||||||
|
File.Move(logToMove, movedLogName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write(string msg, LogType type)
|
||||||
|
{
|
||||||
|
WritingLock.EnterWriteLock();
|
||||||
|
|
||||||
|
string stringType = type.ToString();
|
||||||
|
msg = msg.StripColors();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stringType = Utilities.CurrentLocalization.LocalizationIndex[$"GLOBAL_{type.ToString().ToUpper()}"];
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception) { }
|
||||||
|
|
||||||
|
string LogLine = $"[{DateTime.Now.ToString("MM.dd.yyy HH:mm:ss.fff")}] - {stringType}: {msg}";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
// lets keep it simple and dispose of everything quickly as logging wont be that much (relatively)
|
||||||
|
Console.WriteLine(msg);
|
||||||
|
#else
|
||||||
|
if (type == LogType.Error || type == LogType.Verbose)
|
||||||
|
{
|
||||||
|
Console.WriteLine(LogLine);
|
||||||
|
}
|
||||||
|
File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Well.. It looks like your machine can't event write to the log file. That's something else...");
|
||||||
|
Console.WriteLine(ex.GetExceptionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
WritingLock.ExitWriteLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteVerbose(string msg)
|
public void WriteVerbose(string msg)
|
||||||
{
|
{
|
||||||
_logger.LogInformation(msg);
|
Write(msg, LogType.Verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteDebug(string msg)
|
public void WriteDebug(string msg)
|
||||||
{
|
{
|
||||||
_logger.LogDebug(msg);
|
Write(msg, LogType.Debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteError(string msg)
|
public void WriteError(string msg)
|
||||||
{
|
{
|
||||||
_logger.LogError(msg);
|
Write(msg, LogType.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteInfo(string msg)
|
public void WriteInfo(string msg)
|
||||||
{
|
{
|
||||||
WriteVerbose(msg);
|
Write(msg, LogType.Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteWarning(string msg)
|
public void WriteWarning(string msg)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(msg);
|
Write(msg, LogType.Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteAssert(bool condition, string msg)
|
public void WriteAssert(bool condition, string msg)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if (!condition)
|
||||||
|
Write(msg, LogType.Assert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,6 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
namespace IW4MAdmin.Application.Misc
|
||||||
{
|
{
|
||||||
@ -26,9 +24,10 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
private readonly ApplicationConfiguration _appConfig;
|
private readonly ApplicationConfiguration _appConfig;
|
||||||
private readonly BuildNumber _fallbackVersion = BuildNumber.Parse("99.99.99.99");
|
private readonly BuildNumber _fallbackVersion = BuildNumber.Parse("99.99.99.99");
|
||||||
private readonly int _apiVersion = 1;
|
private readonly int _apiVersion = 1;
|
||||||
|
|
||||||
private bool firstHeartBeat = true;
|
private bool firstHeartBeat = true;
|
||||||
|
|
||||||
public MasterCommunication(ILogger<MasterCommunication> logger, ApplicationConfiguration appConfig, ITranslationLookup translationLookup, IMasterApi apiInstance, IManager manager)
|
public MasterCommunication(ILogger logger, ApplicationConfiguration appConfig, ITranslationLookup translationLookup, IMasterApi apiInstance, IManager manager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_transLookup = translationLookup;
|
_transLookup = translationLookup;
|
||||||
@ -56,7 +55,13 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Unable to retrieve IW4MAdmin version information");
|
_logger.WriteWarning(_transLookup["MANAGER_VERSION_FAIL"]);
|
||||||
|
while (e.InnerException != null)
|
||||||
|
{
|
||||||
|
e = e.InnerException;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.WriteDebug(e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version.CurrentVersionStable == _fallbackVersion)
|
if (version.CurrentVersionStable == _fallbackVersion)
|
||||||
@ -105,12 +110,12 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
catch (System.Net.Http.HttpRequestException e)
|
catch (System.Net.Http.HttpRequestException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not send heartbeat");
|
_logger.WriteWarning($"Could not send heartbeat - {e.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (AggregateException e)
|
catch (AggregateException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not send heartbeat");
|
_logger.WriteWarning($"Could not send heartbeat - {e.Message}");
|
||||||
var exceptions = e.InnerExceptions.Where(ex => ex.GetType() == typeof(ApiException));
|
var exceptions = e.InnerExceptions.Where(ex => ex.GetType() == typeof(ApiException));
|
||||||
|
|
||||||
foreach (var ex in exceptions)
|
foreach (var ex in exceptions)
|
||||||
@ -124,7 +129,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
catch (ApiException e)
|
catch (ApiException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not send heartbeat");
|
_logger.WriteWarning($"Could not send heartbeat - {e.Message}");
|
||||||
if (e.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
if (e.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||||
{
|
{
|
||||||
connected = false;
|
connected = false;
|
||||||
@ -133,7 +138,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not send heartbeat");
|
_logger.WriteWarning($"Could not send heartbeat - {e.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -197,7 +202,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
if (response.ResponseMessage.StatusCode != System.Net.HttpStatusCode.OK)
|
if (response.ResponseMessage.StatusCode != System.Net.HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Non success response code from master is {statusCode}, message is {message}", response.ResponseMessage.StatusCode, response.StringContent);
|
_logger.WriteWarning($"Response code from master is {response.ResponseMessage.StatusCode}, message is {response.StringContent}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
namespace IW4MAdmin.Application.Misc
|
||||||
{
|
{
|
||||||
@ -22,7 +20,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public MetaService(ILogger<MetaService> logger, IDatabaseContextFactory contextFactory)
|
public MetaService(ILogger logger, IDatabaseContextFactory contextFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_metaActions = new Dictionary<MetaType, List<dynamic>>();
|
_metaActions = new Dictionary<MetaType, List<dynamic>>();
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
namespace IW4MAdmin.Application.Misc
|
||||||
{
|
{
|
||||||
@ -12,7 +11,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
private readonly IDictionary<string, IList<object>> _actions;
|
private readonly IDictionary<string, IList<object>> _actions;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public MiddlewareActionHandler(ILogger<MiddlewareActionHandler> logger)
|
public MiddlewareActionHandler(ILogger logger)
|
||||||
{
|
{
|
||||||
_actions = new Dictionary<string, IList<object>>();
|
_actions = new Dictionary<string, IList<object>>();
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -39,7 +38,8 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Failed to invoke middleware action {name}", name);
|
_logger.WriteWarning($"Failed to invoke middleware action {name}");
|
||||||
|
_logger.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,9 @@ using System.Reflection;
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using IW4MAdmin.Application.API.Master;
|
using IW4MAdmin.Application.Misc;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SharedLibraryCore.Configuration;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
namespace IW4MAdmin.Application.Helpers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// implementation of IPluginImporter
|
/// implementation of IPluginImporter
|
||||||
@ -18,19 +15,12 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PluginImporter : IPluginImporter
|
public class PluginImporter : IPluginImporter
|
||||||
{
|
{
|
||||||
private IEnumerable<PluginSubscriptionContent> _pluginSubscription;
|
|
||||||
private static readonly string PLUGIN_DIR = "Plugins";
|
private static readonly string PLUGIN_DIR = "Plugins";
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IRemoteAssemblyHandler _remoteAssemblyHandler;
|
|
||||||
private readonly IMasterApi _masterApi;
|
|
||||||
private readonly ApplicationConfiguration _appConfig;
|
|
||||||
|
|
||||||
public PluginImporter(ILogger<PluginImporter> logger, ApplicationConfiguration appConfig, IMasterApi masterApi, IRemoteAssemblyHandler remoteAssemblyHandler)
|
public PluginImporter(ILogger logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_masterApi = masterApi;
|
|
||||||
_remoteAssemblyHandler = remoteAssemblyHandler;
|
|
||||||
_appConfig = appConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -43,16 +33,16 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
if (Directory.Exists(pluginDir))
|
if (Directory.Exists(pluginDir))
|
||||||
{
|
{
|
||||||
var scriptPluginFiles = Directory.GetFiles(pluginDir, "*.js").AsEnumerable().Union(GetRemoteScripts());
|
string[] scriptPluginFiles = Directory.GetFiles(pluginDir, "*.js");
|
||||||
|
|
||||||
_logger.LogDebug("Discovered {count} potential script plugins", scriptPluginFiles.Count());
|
_logger.WriteInfo($"Discovered {scriptPluginFiles.Length} potential script plugins");
|
||||||
|
|
||||||
if (scriptPluginFiles.Count() > 0)
|
if (scriptPluginFiles.Length > 0)
|
||||||
{
|
{
|
||||||
foreach (string fileName in scriptPluginFiles)
|
foreach (string fileName in scriptPluginFiles)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Discovered script plugin {fileName}", fileName);
|
_logger.WriteInfo($"Discovered script plugin {fileName}");
|
||||||
var plugin = new ScriptPlugin(_logger, fileName);
|
var plugin = new ScriptPlugin(fileName);
|
||||||
yield return plugin;
|
yield return plugin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,70 +62,27 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
if (Directory.Exists(pluginDir))
|
if (Directory.Exists(pluginDir))
|
||||||
{
|
{
|
||||||
var dllFileNames = Directory.GetFiles(pluginDir, "*.dll");
|
var dllFileNames = Directory.GetFiles(pluginDir, "*.dll");
|
||||||
_logger.LogDebug("Discovered {count} potential plugin assemblies", dllFileNames.Length);
|
_logger.WriteInfo($"Discovered {dllFileNames.Length} potential plugin assemblies");
|
||||||
|
|
||||||
if (dllFileNames.Length > 0)
|
if (dllFileNames.Length > 0)
|
||||||
{
|
{
|
||||||
// we only want to load the most recent assembly in case of duplicates
|
var assemblies = dllFileNames.Select(_name => Assembly.LoadFrom(_name));
|
||||||
var assemblies = dllFileNames.Select(_name => Assembly.LoadFrom(_name))
|
|
||||||
.Union(GetRemoteAssemblies())
|
|
||||||
.GroupBy(_assembly => _assembly.FullName).Select(_assembly => _assembly.OrderByDescending(_assembly => _assembly.GetName().Version).First());
|
|
||||||
|
|
||||||
pluginTypes = assemblies
|
pluginTypes = assemblies
|
||||||
.SelectMany(_asm => _asm.GetTypes())
|
.SelectMany(_asm => _asm.GetTypes())
|
||||||
.Where(_assemblyType => _assemblyType.GetInterface(nameof(IPlugin), false) != null);
|
.Where(_assemblyType => _assemblyType.GetInterface(nameof(IPlugin), false) != null);
|
||||||
|
|
||||||
_logger.LogDebug("Discovered {count} plugin implementations", pluginTypes.Count());
|
_logger.WriteInfo($"Discovered {pluginTypes.Count()} plugin implementations");
|
||||||
|
|
||||||
commandTypes = assemblies
|
commandTypes = assemblies
|
||||||
.SelectMany(_asm => _asm.GetTypes())
|
.SelectMany(_asm => _asm.GetTypes())
|
||||||
.Where(_assemblyType => _assemblyType.IsClass && _assemblyType.BaseType == typeof(Command));
|
.Where(_assemblyType => _assemblyType.IsClass && _assemblyType.BaseType == typeof(Command));
|
||||||
|
|
||||||
_logger.LogDebug("Discovered {count} plugin commands", commandTypes.Count());
|
_logger.WriteInfo($"Discovered {commandTypes.Count()} plugin commands");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (pluginTypes, commandTypes);
|
return (pluginTypes, commandTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Assembly> GetRemoteAssemblies()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_pluginSubscription == null)
|
|
||||||
_pluginSubscription = _masterApi.GetPluginSubscription(Guid.Parse(_appConfig.Id), _appConfig.SubscriptionId).Result;
|
|
||||||
|
|
||||||
return _remoteAssemblyHandler.DecryptAssemblies(_pluginSubscription.Where(sub => sub.Type == PluginType.Binary).Select(sub => sub.Content).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Could not load remote assemblies");
|
|
||||||
return Enumerable.Empty<Assembly>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<string> GetRemoteScripts()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_pluginSubscription == null)
|
|
||||||
_pluginSubscription = _masterApi.GetPluginSubscription(Guid.Parse(_appConfig.Id), _appConfig.SubscriptionId).Result;
|
|
||||||
|
|
||||||
return _remoteAssemblyHandler.DecryptScripts(_pluginSubscription.Where(sub => sub.Type == PluginType.Script).Select(sub => sub.Content).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex,"Could not load remote scripts");
|
|
||||||
return Enumerable.Empty<string>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PluginType
|
|
||||||
{
|
|
||||||
Binary,
|
|
||||||
Script
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
using SharedLibraryCore.Configuration;
|
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
|
||||||
{
|
|
||||||
public class RemoteAssemblyHandler : IRemoteAssemblyHandler
|
|
||||||
{
|
|
||||||
private const int keyLength = 32;
|
|
||||||
private const int tagLength = 16;
|
|
||||||
private const int nonceLength = 12;
|
|
||||||
private const int iterationCount = 10000;
|
|
||||||
|
|
||||||
private readonly ApplicationConfiguration _appconfig;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public RemoteAssemblyHandler(ILogger<RemoteAssemblyHandler> logger, ApplicationConfiguration appconfig)
|
|
||||||
{
|
|
||||||
_appconfig = appconfig;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Assembly> DecryptAssemblies(string[] encryptedAssemblies)
|
|
||||||
{
|
|
||||||
return DecryptContent(encryptedAssemblies)
|
|
||||||
.Select(decryptedAssembly => Assembly.Load(decryptedAssembly));
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> DecryptScripts(string[] encryptedScripts)
|
|
||||||
{
|
|
||||||
return DecryptContent(encryptedScripts).Select(decryptedScript => Encoding.UTF8.GetString(decryptedScript));
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[][] DecryptContent(string[] content)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_appconfig.Id) || string.IsNullOrWhiteSpace(_appconfig.SubscriptionId))
|
|
||||||
{
|
|
||||||
_logger.LogWarning($"{nameof(_appconfig.Id)} and {nameof(_appconfig.SubscriptionId)} must be provided to attempt loading remote assemblies/scripts");
|
|
||||||
return new byte[0][];
|
|
||||||
}
|
|
||||||
|
|
||||||
var assemblies = content.Select(piece =>
|
|
||||||
{
|
|
||||||
byte[] byteContent = Convert.FromBase64String(piece);
|
|
||||||
byte[] encryptedContent = byteContent.Take(byteContent.Length - (tagLength + nonceLength)).ToArray();
|
|
||||||
byte[] tag = byteContent.Skip(byteContent.Length - (tagLength + nonceLength)).Take(tagLength).ToArray();
|
|
||||||
byte[] nonce = byteContent.Skip(byteContent.Length - nonceLength).Take(nonceLength).ToArray();
|
|
||||||
byte[] decryptedContent = new byte[encryptedContent.Length];
|
|
||||||
|
|
||||||
var keyGen = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(_appconfig.SubscriptionId), Encoding.UTF8.GetBytes(_appconfig.Id.ToString()), iterationCount, HashAlgorithmName.SHA512);
|
|
||||||
var encryption = new AesGcm(keyGen.GetBytes(keyLength));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
encryption.Decrypt(nonce, encryptedContent, tag, decryptedContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (CryptographicException ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Could not decrypt remote plugin assemblies");
|
|
||||||
}
|
|
||||||
|
|
||||||
return decryptedContent;
|
|
||||||
});
|
|
||||||
|
|
||||||
return assemblies.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,9 +4,7 @@ using SharedLibraryCore.Configuration;
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
namespace IW4MAdmin.Application.Misc
|
||||||
{
|
{
|
||||||
@ -16,15 +14,13 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
public class ScriptCommand : Command
|
public class ScriptCommand : Command
|
||||||
{
|
{
|
||||||
private readonly Action<GameEvent> _executeAction;
|
private readonly Action<GameEvent> _executeAction;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public ScriptCommand(string name, string alias, string description, bool isTargetRequired, Permission permission,
|
public ScriptCommand(string name, string alias, string description, bool isTargetRequired, Permission permission,
|
||||||
CommandArgument[] args, Action<GameEvent> executeAction, CommandConfiguration config, ITranslationLookup layout, ILogger<ScriptCommand> logger)
|
CommandArgument[] args, Action<GameEvent> executeAction, CommandConfiguration config, ITranslationLookup layout)
|
||||||
: base(config, layout)
|
: base(config, layout)
|
||||||
{
|
{
|
||||||
|
|
||||||
_executeAction = executeAction;
|
_executeAction = executeAction;
|
||||||
_logger = logger;
|
|
||||||
Name = name;
|
Name = name;
|
||||||
Alias = alias;
|
Alias = alias;
|
||||||
Description = description;
|
Description = description;
|
||||||
@ -33,21 +29,14 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
Arguments = args;
|
Arguments = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task ExecuteAsync(GameEvent e)
|
public override Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
if (_executeAction == null)
|
if (_executeAction == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"No execute action defined for command \"{Name}\"");
|
throw new InvalidOperationException($"No execute action defined for command \"{Name}\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
return Task.Run(() => _executeAction(E));
|
||||||
{
|
|
||||||
await Task.Run(() => _executeAction(e));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Failed to execute ScriptCommand action for command {command} {@event}", Name, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using Jint;
|
||||||
using Jint;
|
|
||||||
using Jint.Native;
|
using Jint.Native;
|
||||||
using Jint.Runtime;
|
using Jint.Runtime;
|
||||||
using Microsoft.CSharp.RuntimeBinder;
|
using Microsoft.CSharp.RuntimeBinder;
|
||||||
@ -13,9 +12,6 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
namespace IW4MAdmin.Application.Misc
|
||||||
{
|
{
|
||||||
@ -43,11 +39,9 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
private readonly SemaphoreSlim _onProcessing;
|
private readonly SemaphoreSlim _onProcessing;
|
||||||
private bool successfullyLoaded;
|
private bool successfullyLoaded;
|
||||||
private readonly List<string> _registeredCommandNames;
|
private readonly List<string> _registeredCommandNames;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public ScriptPlugin(ILogger logger, string filename, string workingDirectory = null)
|
public ScriptPlugin(string filename, string workingDirectory = null)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
_fileName = filename;
|
_fileName = filename;
|
||||||
Watcher = new FileSystemWatcher()
|
Watcher = new FileSystemWatcher()
|
||||||
{
|
{
|
||||||
@ -90,7 +84,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
foreach (string commandName in _registeredCommandNames)
|
foreach (string commandName in _registeredCommandNames)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Removing plugin registered command {command}", commandName);
|
manager.GetLogger(0).WriteDebug($"Removing plugin registered command \"{commandName}\"");
|
||||||
manager.RemoveCommandByName(commandName);
|
manager.RemoveCommandByName(commandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +129,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
{
|
{
|
||||||
foreach (var command in GenerateScriptCommands(commands, scriptCommandFactory))
|
foreach (var command in GenerateScriptCommands(commands, scriptCommandFactory))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Adding plugin registered command {commandName}", command.Name);
|
manager.GetLogger(0).WriteDebug($"Adding plugin registered command \"{command.Name}\"");
|
||||||
manager.AddAdditionalCommand(command);
|
manager.AddAdditionalCommand(command);
|
||||||
_registeredCommandNames.Add(command.Name);
|
_registeredCommandNames.Add(command.Name);
|
||||||
}
|
}
|
||||||
@ -173,20 +167,12 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
catch (JavaScriptException ex)
|
catch (JavaScriptException ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex,
|
throw new PluginException($"An error occured while initializing script plugin: {ex.Error} (Line: {ex.Location.Start.Line}, Character: {ex.Location.Start.Column})") { PluginFile = _fileName };
|
||||||
"Encountered JavaScript runtime error while executing {methodName} for script plugin {plugin} initialization {@locationInfo}",
|
|
||||||
nameof(OnLoadAsync), _fileName, ex.Location);
|
|
||||||
|
|
||||||
throw new PluginException("An error occured while initializing script plugin");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
_logger.LogError(ex,
|
throw;
|
||||||
"Encountered unexpected error while running {methodName} for script plugin {plugin}",
|
|
||||||
nameof(OnLoadAsync), _fileName);
|
|
||||||
|
|
||||||
throw new PluginException("An unexpected error occured while initializing script plugin");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@ -211,29 +197,10 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
_scriptEngine.SetValue("_IW4MAdminClient", Utilities.IW4MAdminClient(S));
|
_scriptEngine.SetValue("_IW4MAdminClient", Utilities.IW4MAdminClient(S));
|
||||||
_scriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue();
|
_scriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (JavaScriptException ex)
|
catch
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", S.ToString()))
|
throw;
|
||||||
{
|
|
||||||
_logger.LogError(ex,
|
|
||||||
"Encountered JavaScript runtime error while executing {methodName} for script plugin {plugin} with event type {eventType} {@locationInfo}",
|
|
||||||
nameof(OnEventAsync), _fileName, E.Type, ex.Location);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new PluginException($"An error occured while executing action for script plugin");
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
using (LogContext.PushProperty("Server", S.ToString()))
|
|
||||||
{
|
|
||||||
_logger.LogError(e,
|
|
||||||
"Encountered unexpected error while running {methodName} for script plugin {plugin} with event type {eventType}",
|
|
||||||
nameof(OnEventAsync), _fileName, E.Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new PluginException($"An error occured while executing action for script plugin");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@ -248,7 +215,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
public Task OnLoadAsync(IManager manager)
|
public Task OnLoadAsync(IManager manager)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("OnLoad executing for {name}", Name);
|
manager.GetLogger(0).WriteDebug($"OnLoad executing for {Name}");
|
||||||
_scriptEngine.SetValue("_manager", manager);
|
_scriptEngine.SetValue("_manager", manager);
|
||||||
return Task.FromResult(_scriptEngine.Execute("plugin.onLoadAsync(_manager)").GetCompletionValue());
|
return Task.FromResult(_scriptEngine.Execute("plugin.onLoadAsync(_manager)").GetCompletionValue());
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,6 @@ using System.Net.Sockets;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RCon
|
namespace IW4MAdmin.Application.RCon
|
||||||
{
|
{
|
||||||
@ -26,12 +23,11 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
public IPEndPoint Endpoint { get; private set; }
|
public IPEndPoint Endpoint { get; private set; }
|
||||||
public string RConPassword { get; private set; }
|
public string RConPassword { get; private set; }
|
||||||
|
|
||||||
private IRConParser parser;
|
|
||||||
private IRConParserConfiguration config;
|
private IRConParserConfiguration config;
|
||||||
private readonly ILogger _log;
|
private readonly ILogger _log;
|
||||||
private readonly Encoding _gameEncoding;
|
private readonly Encoding _gameEncoding;
|
||||||
|
|
||||||
public RConConnection(string ipAddress, int port, string password, ILogger<RConConnection> log, Encoding gameEncoding)
|
public RConConnection(string ipAddress, int port, string password, ILogger log, Encoding gameEncoding)
|
||||||
{
|
{
|
||||||
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
||||||
_gameEncoding = gameEncoding;
|
_gameEncoding = gameEncoding;
|
||||||
@ -39,10 +35,9 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
_log = log;
|
_log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConfiguration(IRConParser parser)
|
public void SetConfiguration(IRConParserConfiguration config)
|
||||||
{
|
{
|
||||||
this.parser = parser;
|
this.config = config;
|
||||||
config = parser.Configuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
|
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
|
||||||
@ -54,8 +49,9 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
var connectionState = ActiveQueries[this.Endpoint];
|
var connectionState = ActiveQueries[this.Endpoint];
|
||||||
|
|
||||||
_log.LogDebug("Waiting for semaphore to be released [{endpoint}]", Endpoint);
|
#if DEBUG == true
|
||||||
|
_log.WriteDebug($"Waiting for semaphore to be released [{this.Endpoint}]");
|
||||||
|
#endif
|
||||||
// enter the semaphore so only one query is sent at a time per server.
|
// enter the semaphore so only one query is sent at a time per server.
|
||||||
await connectionState.OnComplete.WaitAsync();
|
await connectionState.OnComplete.WaitAsync();
|
||||||
|
|
||||||
@ -68,8 +64,10 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
connectionState.LastQuery = DateTime.Now;
|
connectionState.LastQuery = DateTime.Now;
|
||||||
|
|
||||||
_log.LogDebug("Semaphore has been released [{endpoint}]", Endpoint);
|
#if DEBUG == true
|
||||||
_log.LogDebug("Query {@queryInfo}", new { endpoint=Endpoint.ToString(), type, parameters });
|
_log.WriteDebug($"Semaphore has been released [{this.Endpoint}]");
|
||||||
|
_log.WriteDebug($"Query [{this.Endpoint},{type.ToString()},{parameters}]");
|
||||||
|
#endif
|
||||||
|
|
||||||
byte[] payload = null;
|
byte[] payload = null;
|
||||||
bool waitForResponse = config.WaitForResponse;
|
bool waitForResponse = config.WaitForResponse;
|
||||||
@ -114,31 +112,15 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
// this happens when someone tries to send something that can't be converted into a 7 bit character set
|
// this happens when someone tries to send something that can't be converted into a 7 bit character set
|
||||||
// e.g: emoji -> windows-1252
|
// e.g: emoji -> windows-1252
|
||||||
catch (OverflowException ex)
|
catch (OverflowException)
|
||||||
{
|
{
|
||||||
connectionState.OnComplete.Release(1);
|
connectionState.OnComplete.Release(1);
|
||||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
throw new NetworkException($"Invalid character encountered when converting encodings - {parameters}");
|
||||||
{
|
|
||||||
_log.LogError(ex, "Could not convert RCon data payload to desired encoding {encoding} {params}",
|
|
||||||
_gameEncoding.EncodingName, parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RConException($"Invalid character encountered when converting encodings");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[][] response = null;
|
byte[][] response = null;
|
||||||
|
|
||||||
retrySend:
|
retrySend:
|
||||||
if (connectionState.ConnectionAttempts > 1)
|
|
||||||
{
|
|
||||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
|
||||||
{
|
|
||||||
_log.LogInformation(
|
|
||||||
"Retrying RCon message ({connectionAttempts}/{allowedConnectionFailures} attempts) with parameters {payload}",
|
|
||||||
connectionState.ConnectionAttempts,
|
|
||||||
StaticHelpers.AllowedConnectionFails, parameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
|
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
|
||||||
{
|
{
|
||||||
DontFragment = true,
|
DontFragment = true,
|
||||||
@ -151,19 +133,16 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
connectionState.OnReceivedData.Reset();
|
connectionState.OnReceivedData.Reset();
|
||||||
connectionState.ConnectionAttempts++;
|
connectionState.ConnectionAttempts++;
|
||||||
connectionState.BytesReadPerSegment.Clear();
|
connectionState.BytesReadPerSegment.Clear();
|
||||||
bool exceptionCaught = false;
|
#if DEBUG == true
|
||||||
|
_log.WriteDebug($"Sending {payload.Length} bytes to [{this.Endpoint}] ({connectionState.ConnectionAttempts}/{StaticHelpers.AllowedConnectionFails})");
|
||||||
_log.LogDebug("Sending {payloadLength} bytes to [{endpoint}] ({connectionAttempts}/{allowedConnectionFailures})",
|
#endif
|
||||||
payload.Length, Endpoint, connectionState.ConnectionAttempts, StaticHelpers.AllowedConnectionFails);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
response = await SendPayloadAsync(payload, waitForResponse);
|
||||||
response = await SendPayloadAsync(payload, waitForResponse, parser.OverrideTimeoutForCommand(parameters));
|
|
||||||
|
|
||||||
if ((response.Length == 0 || response[0].Length == 0) && waitForResponse)
|
if ((response.Length == 0 || response[0].Length == 0) && waitForResponse)
|
||||||
{
|
{
|
||||||
throw new RConException("Expected response but got 0 bytes back");
|
throw new NetworkException("Expected response but got 0 bytes back");
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionState.ConnectionAttempts = 0;
|
connectionState.ConnectionAttempts = 0;
|
||||||
@ -171,28 +150,18 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// we want to retry with a delay
|
|
||||||
if (connectionState.ConnectionAttempts < StaticHelpers.AllowedConnectionFails)
|
if (connectionState.ConnectionAttempts < StaticHelpers.AllowedConnectionFails)
|
||||||
{
|
{
|
||||||
exceptionCaught = true;
|
await Task.Delay(StaticHelpers.FloodProtectionInterval);
|
||||||
await Task.Delay(StaticHelpers.SocketTimeout(connectionState.ConnectionAttempts));
|
|
||||||
goto retrySend;
|
goto retrySend;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMUNICATION"].FormatExt(Endpoint));
|
||||||
{
|
|
||||||
_log.LogWarning(
|
|
||||||
"Made {connectionAttempts} attempts to send RCon data to server, but received no response",
|
|
||||||
connectionState.ConnectionAttempts);
|
|
||||||
}
|
|
||||||
connectionState.ConnectionAttempts = 0;
|
|
||||||
throw new NetworkException("Reached maximum retry attempts to send RCon data to server");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// we don't want to release if we're going to retry the query
|
if (connectionState.OnComplete.CurrentCount == 0)
|
||||||
if (connectionState.OnComplete.CurrentCount == 0 && !exceptionCaught)
|
|
||||||
{
|
{
|
||||||
connectionState.OnComplete.Release(1);
|
connectionState.OnComplete.Release(1);
|
||||||
}
|
}
|
||||||
@ -201,22 +170,23 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
if (response.Length == 0)
|
if (response.Length == 0)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Received empty response for RCon request {@query}", new { endpoint=Endpoint.ToString(), type, parameters });
|
_log.WriteWarning($"Received empty response for request [{type.ToString()}, {parameters}, {Endpoint.ToString()}]");
|
||||||
return new string[0];
|
return new string[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
string responseString = type == StaticHelpers.QueryType.COMMAND_STATUS ?
|
string responseString = type == StaticHelpers.QueryType.COMMAND_STATUS ?
|
||||||
ReassembleSegmentedStatus(response) : RecombineMessages(response);
|
ReassembleSegmentedStatus(response) :
|
||||||
|
_gameEncoding.GetString(response[0]) + '\n';
|
||||||
|
|
||||||
// note: not all games respond if the pasword is wrong or not set
|
// note: not all games respond if the pasword is wrong or not set
|
||||||
if (responseString.Contains("Invalid password") || responseString.Contains("rconpassword"))
|
if (responseString.Contains("Invalid password") || responseString.Contains("rconpassword"))
|
||||||
{
|
{
|
||||||
throw new RConException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_INVALID"]);
|
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_INVALID"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseString.Contains("rcon_password"))
|
if (responseString.Contains("rcon_password"))
|
||||||
{
|
{
|
||||||
throw new RConException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_NOTSET"]);
|
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_NOTSET"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseString.Contains(config.ServerNotRunningResponse))
|
if (responseString.Contains(config.ServerNotRunningResponse))
|
||||||
@ -229,13 +199,7 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
if (headerSplit.Length != 2)
|
if (headerSplit.Length != 2)
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
throw new NetworkException("Unexpected response header from server");
|
||||||
{
|
|
||||||
_log.LogWarning("Invalid response header from server. Expected {expected}, but got {response}",
|
|
||||||
config.CommandPrefixes.RConResponse, headerSplit.FirstOrDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RConException("Unexpected response header from server");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] splitResponse = headerSplit.Last().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
string[] splitResponse = headerSplit.Last().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
@ -270,36 +234,7 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
return string.Join("", splitStatusStrings);
|
return string.Join("", splitStatusStrings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private async Task<byte[][]> SendPayloadAsync(byte[] payload, bool waitForResponse)
|
||||||
/// Recombines multiple game messages into one
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="payload"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string RecombineMessages(byte[][] payload)
|
|
||||||
{
|
|
||||||
if (payload.Length == 1)
|
|
||||||
{
|
|
||||||
return _gameEncoding.GetString(payload[0]).TrimEnd('\n') + '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
for (int i = 0; i < payload.Length; i++)
|
|
||||||
{
|
|
||||||
string message = _gameEncoding.GetString(payload[i]).TrimEnd('\n') + '\n';
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
message = message.Replace(config.CommandPrefixes.RConResponse, "");
|
|
||||||
}
|
|
||||||
builder.Append(message);
|
|
||||||
}
|
|
||||||
builder.Append('\n');
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<byte[][]> SendPayloadAsync(byte[] payload, bool waitForResponse, TimeSpan overrideTimeout)
|
|
||||||
{
|
{
|
||||||
var connectionState = ActiveQueries[this.Endpoint];
|
var connectionState = ActiveQueries[this.Endpoint];
|
||||||
var rconSocket = (Socket)connectionState.SendEventArgs.UserToken;
|
var rconSocket = (Socket)connectionState.SendEventArgs.UserToken;
|
||||||
@ -323,17 +258,11 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
if (sendDataPending)
|
if (sendDataPending)
|
||||||
{
|
{
|
||||||
// the send has not been completed asynchronously
|
// the send has not been completed asyncronously
|
||||||
// this really shouldn't ever happen because it's UDP
|
if (!await Task.Run(() => connectionState.OnSentData.Wait(StaticHelpers.SocketTimeout)))
|
||||||
if (!await Task.Run(() => connectionState.OnSentData.Wait(StaticHelpers.SocketTimeout(1))))
|
|
||||||
{
|
{
|
||||||
using(LogContext.PushProperty("Server", Endpoint.ToString()))
|
|
||||||
{
|
|
||||||
_log.LogWarning("Socket timed out while sending RCon data on attempt {attempt}",
|
|
||||||
connectionState.ConnectionAttempts);
|
|
||||||
}
|
|
||||||
rconSocket.Close();
|
rconSocket.Close();
|
||||||
throw new NetworkException("Timed out sending RCon data", rconSocket);
|
throw new NetworkException("Timed out sending data", rconSocket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,37 +278,15 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
if (receiveDataPending)
|
if (receiveDataPending)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Waiting to asynchronously receive data on attempt #{connectionAttempts}", connectionState.ConnectionAttempts);
|
if (!await Task.Run(() => connectionState.OnReceivedData.Wait(10000)))
|
||||||
if (!await Task.Run(() => connectionState.OnReceivedData.Wait(
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
StaticHelpers.SocketTimeout(connectionState.ConnectionAttempts),
|
|
||||||
overrideTimeout
|
|
||||||
}.Max())))
|
|
||||||
{
|
{
|
||||||
if (connectionState.ConnectionAttempts > 1) // this reduces some spam for unstable connections
|
|
||||||
{
|
|
||||||
using (LogContext.PushProperty("Server", Endpoint.ToString()))
|
|
||||||
{
|
|
||||||
_log.LogWarning(
|
|
||||||
"Socket timed out while waiting for RCon response on attempt {attempt} with timeout delay of {timeout}",
|
|
||||||
connectionState.ConnectionAttempts,
|
|
||||||
StaticHelpers.SocketTimeout(connectionState.ConnectionAttempts));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rconSocket.Close();
|
rconSocket.Close();
|
||||||
throw new NetworkException("Timed out receiving RCon response", rconSocket);
|
throw new NetworkException("Timed out waiting for response", rconSocket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rconSocket.Close();
|
rconSocket.Close();
|
||||||
|
|
||||||
return GetResponseData(connectionState);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[][] GetResponseData(ConnectionState connectionState)
|
|
||||||
{
|
|
||||||
var responseList = new List<byte[]>();
|
var responseList = new List<byte[]>();
|
||||||
int totalBytesRead = 0;
|
int totalBytesRead = 0;
|
||||||
|
|
||||||
@ -398,7 +305,9 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
private void OnDataReceived(object sender, SocketAsyncEventArgs e)
|
private void OnDataReceived(object sender, SocketAsyncEventArgs e)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Read {bytesTransferred} bytes from {endpoint}", e.BytesTransferred, e.RemoteEndPoint);
|
#if DEBUG == true
|
||||||
|
_log.WriteDebug($"Read {e.BytesTransferred} bytes from {e.RemoteEndPoint.ToString()}");
|
||||||
|
#endif
|
||||||
|
|
||||||
// this occurs when we close the socket
|
// this occurs when we close the socket
|
||||||
if (e.BytesTransferred == 0)
|
if (e.BytesTransferred == 0)
|
||||||
@ -421,7 +330,9 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
if (!sock.ReceiveAsync(state.ReceiveEventArgs))
|
if (!sock.ReceiveAsync(state.ReceiveEventArgs))
|
||||||
{
|
{
|
||||||
_log.LogDebug("Read {bytesTransferred} synchronous bytes from {endpoint}", state.ReceiveEventArgs.BytesTransferred, e.RemoteEndPoint);
|
#if DEBUG == true
|
||||||
|
_log.WriteDebug($"Read {state.ReceiveEventArgs.BytesTransferred} synchronous bytes from {e.RemoteEndPoint.ToString()}");
|
||||||
|
#endif
|
||||||
// we need to increment this here because the callback isn't executed if there's no pending IO
|
// we need to increment this here because the callback isn't executed if there's no pending IO
|
||||||
state.BytesReadPerSegment.Add(state.ReceiveEventArgs.BytesTransferred);
|
state.BytesReadPerSegment.Add(state.ReceiveEventArgs.BytesTransferred);
|
||||||
ActiveQueries[this.Endpoint].OnReceivedData.Set();
|
ActiveQueries[this.Endpoint].OnReceivedData.Set();
|
||||||
@ -443,7 +354,9 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
|
|
||||||
private void OnDataSent(object sender, SocketAsyncEventArgs e)
|
private void OnDataSent(object sender, SocketAsyncEventArgs e)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Sent {byteCount} bytes to {endpoint}", e.Buffer?.Length, e.ConnectSocket?.RemoteEndPoint);
|
#if DEBUG == true
|
||||||
|
_log.WriteDebug($"Sent {e.Buffer?.Length} bytes to {e.ConnectSocket?.RemoteEndPoint?.ToString()}");
|
||||||
|
#endif
|
||||||
ActiveQueries[this.Endpoint].OnSentData.Set();
|
ActiveQueries[this.Endpoint].OnSentData.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,14 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
namespace IW4MAdmin.Application.RconParsers
|
||||||
{
|
{
|
||||||
public class BaseRConParser : IRConParser
|
public class BaseRConParser : IRConParser
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
public BaseRConParser(IParserRegexFactory parserRegexFactory)
|
||||||
|
|
||||||
public BaseRConParser(ILogger<BaseRConParser> logger, IParserRegexFactory parserRegexFactory)
|
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
Configuration = new DynamicRConParserConfiguration(parserRegexFactory)
|
Configuration = new DynamicRConParserConfiguration(parserRegexFactory)
|
||||||
{
|
{
|
||||||
CommandPrefixes = new CommandPrefix()
|
CommandPrefixes = new CommandPrefix()
|
||||||
@ -81,22 +76,7 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
string[] lineSplit;
|
string[] lineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.GET_DVAR, dvarName);
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.GET_DVAR, dvarName);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (fallbackValue == null)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
lineSplit = new string[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
string response = string.Join('\n', lineSplit).TrimEnd('\0');
|
string response = string.Join('\n', lineSplit).TrimEnd('\0');
|
||||||
var match = Regex.Match(response, Configuration.Dvar.Pattern);
|
var match = Regex.Match(response, Configuration.Dvar.Pattern);
|
||||||
|
|
||||||
@ -138,7 +118,12 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
public virtual async Task<(List<EFClient>, string, string)> GetStatusAsync(IRConConnection connection)
|
public virtual async Task<(List<EFClient>, string, string)> GetStatusAsync(IRConConnection connection)
|
||||||
{
|
{
|
||||||
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
|
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
|
||||||
_logger.LogDebug("Status Response {@response}", (object)response);
|
#if DEBUG
|
||||||
|
foreach (var line in response)
|
||||||
|
{
|
||||||
|
Console.WriteLine(line);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return (ClientsFromStatus(response), MapFromStatus(response), GameTypeFromStatus(response));
|
return (ClientsFromStatus(response), MapFromStatus(response), GameTypeFromStatus(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,16 +263,5 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
public T GetDefaultDvarValue<T>(string dvarName) => Configuration.DefaultDvarValues.ContainsKey(dvarName) ?
|
public T GetDefaultDvarValue<T>(string dvarName) => Configuration.DefaultDvarValues.ContainsKey(dvarName) ?
|
||||||
(T)Convert.ChangeType(Configuration.DefaultDvarValues[dvarName], typeof(T)) :
|
(T)Convert.ChangeType(Configuration.DefaultDvarValues[dvarName], typeof(T)) :
|
||||||
default;
|
default;
|
||||||
|
|
||||||
public TimeSpan OverrideTimeoutForCommand(string command)
|
|
||||||
{
|
|
||||||
if (command.Contains("map_rotate", StringComparison.InvariantCultureIgnoreCase) ||
|
|
||||||
command.StartsWith("map ", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
return TimeSpan.FromSeconds(30);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TimeSpan.Zero;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
namespace IW4MAdmin.Application.RconParsers
|
||||||
{
|
{
|
||||||
@ -9,7 +8,7 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
sealed internal class DynamicRConParser : BaseRConParser
|
sealed internal class DynamicRConParser : BaseRConParser
|
||||||
{
|
{
|
||||||
public DynamicRConParser(ILogger<BaseRConParser> logger, IParserRegexFactory parserRegexFactory) : base(logger, parserRegexFactory)
|
public DynamicRConParser(IParserRegexFactory parserRegexFactory) : base(parserRegexFactory)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
GameFiles\IW4x\userraw\scripts\_commands.gsc = GameFiles\IW4x\userraw\scripts\_commands.gsc
|
GameFiles\IW4x\userraw\scripts\_commands.gsc = GameFiles\IW4x\userraw\scripts\_commands.gsc
|
||||||
GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc = GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc
|
GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc = GameFiles\IW4x\userraw\scripts\_customcallbacks.gsc
|
||||||
DeploymentFiles\deployment-pipeline.yml = DeploymentFiles\deployment-pipeline.yml
|
PostPublish.ps1 = PostPublish.ps1
|
||||||
DeploymentFiles\PostPublish.ps1 = DeploymentFiles\PostPublish.ps1
|
pre-release-pipeline.yml = pre-release-pipeline.yml
|
||||||
README.md = README.md
|
README.md = README.md
|
||||||
|
RunPublishPre.cmd = RunPublishPre.cmd
|
||||||
|
RunPublishRelease.cmd = RunPublishRelease.cmd
|
||||||
version.txt = version.txt
|
version.txt = version.txt
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
@ -35,7 +37,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug
|
|||||||
Plugins\ScriptPlugins\ActionOnReport.js = Plugins\ScriptPlugins\ActionOnReport.js
|
Plugins\ScriptPlugins\ActionOnReport.js = Plugins\ScriptPlugins\ActionOnReport.js
|
||||||
Plugins\ScriptPlugins\ParserCoD4x.js = Plugins\ScriptPlugins\ParserCoD4x.js
|
Plugins\ScriptPlugins\ParserCoD4x.js = Plugins\ScriptPlugins\ParserCoD4x.js
|
||||||
Plugins\ScriptPlugins\ParserIW4x.js = Plugins\ScriptPlugins\ParserIW4x.js
|
Plugins\ScriptPlugins\ParserIW4x.js = Plugins\ScriptPlugins\ParserIW4x.js
|
||||||
Plugins\ScriptPlugins\ParserIW6x.js = Plugins\ScriptPlugins\ParserIW6x.js
|
|
||||||
Plugins\ScriptPlugins\ParserPIW5.js = Plugins\ScriptPlugins\ParserPIW5.js
|
Plugins\ScriptPlugins\ParserPIW5.js = Plugins\ScriptPlugins\ParserPIW5.js
|
||||||
Plugins\ScriptPlugins\ParserPT6.js = Plugins\ScriptPlugins\ParserPT6.js
|
Plugins\ScriptPlugins\ParserPT6.js = Plugins\ScriptPlugins\ParserPT6.js
|
||||||
Plugins\ScriptPlugins\ParserRektT5M.js = Plugins\ScriptPlugins\ParserRektT5M.js
|
Plugins\ScriptPlugins\ParserRektT5M.js = Plugins\ScriptPlugins\ParserRektT5M.js
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
|
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
using LiveRadar.Configuration;
|
using LiveRadar.Configuration;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Configuration;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace LiveRadar
|
namespace LiveRadar
|
||||||
{
|
{
|
||||||
@ -22,13 +21,11 @@ namespace LiveRadar
|
|||||||
private readonly Dictionary<string, long> _botGuidLookups;
|
private readonly Dictionary<string, long> _botGuidLookups;
|
||||||
private bool addedPage;
|
private bool addedPage;
|
||||||
private readonly object lockObject = new object();
|
private readonly object lockObject = new object();
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public Plugin(ILogger<Plugin> logger, IConfigurationHandlerFactory configurationHandlerFactory)
|
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory)
|
||||||
{
|
{
|
||||||
_configurationHandler = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
_configurationHandler = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
||||||
_botGuidLookups = new Dictionary<string, long>();
|
_botGuidLookups = new Dictionary<string, long>();
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnEventAsync(GameEvent E, Server S)
|
public Task OnEventAsync(GameEvent E, Server S)
|
||||||
@ -83,7 +80,8 @@ namespace LiveRadar
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogError(e, "Could not parse live radar output: {data}", e.Data);
|
S.Logger.WriteWarning($"Could not parse live radar output: {e.Data}");
|
||||||
|
S.Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
var rconParser;
|
|
||||||
var eventParser;
|
|
||||||
|
|
||||||
var plugin = {
|
|
||||||
author: 'Xerxes, RaidMax',
|
|
||||||
version: 0.2,
|
|
||||||
name: 'IW6x Parser',
|
|
||||||
isParser: true,
|
|
||||||
|
|
||||||
onEventAsync: function (gameEvent, server) {
|
|
||||||
},
|
|
||||||
|
|
||||||
onLoadAsync: function (manager) {
|
|
||||||
rconParser = manager.GenerateDynamicRConParser(this.name);
|
|
||||||
eventParser = manager.GenerateDynamicEventParser(this.name);
|
|
||||||
|
|
||||||
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
|
||||||
rconParser.Configuration.CommandPrefixes.Say = 'say {0}';
|
|
||||||
rconParser.Configuration.CommandPrefixes.Kick = 'clientkick {0} "{1}"';
|
|
||||||
rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0} "{1}"';
|
|
||||||
rconParser.Configuration.CommandPrefixes.TempBan = 'clientkick {0} "{1}"';
|
|
||||||
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
|
|
||||||
rconParser.Configuration.Dvar.Pattern = '^ *\\"(.+)\\" is: \\"(.+)?\\" default: \\"(.+)?\\"\\n(?:latched: \\"(.+)?\\"\\n)? *(.+)$';
|
|
||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(Yes|No) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$';
|
|
||||||
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';
|
|
||||||
rconParser.Configuration.WaitForResponse = false;
|
|
||||||
rconParser.Configuration.Status.AddMapping(102, 4);
|
|
||||||
rconParser.Configuration.Status.AddMapping(103, 5);
|
|
||||||
rconParser.Configuration.Status.AddMapping(104, 6);
|
|
||||||
rconParser.Configuration.DefaultDvarValues.Add('g_log', 'games_mp.log'); // todo: remove this once proper log support is implemented
|
|
||||||
rconParser.Configuration.DefaultDvarValues.Add('g_logsync', '1'); // todo: remove this once proper log support is implemented
|
|
||||||
|
|
||||||
rconParser.Version = 'IW6 MP 3.15 build 2 Sat Sep 14 2013 03:58:30PM win64';
|
|
||||||
rconParser.GameName = 4; // IW6
|
|
||||||
eventParser.Version = 'IW6 MP 3.15 build 2 Sat Sep 14 2013 03:58:30PM win64';
|
|
||||||
eventParser.GameName = 4; // IW6
|
|
||||||
eventParser.Configuration.GameDirectory = 'iw6x';
|
|
||||||
},
|
|
||||||
|
|
||||||
onUnloadAsync: function () {
|
|
||||||
},
|
|
||||||
|
|
||||||
onTickAsync: function (server) {
|
|
||||||
}
|
|
||||||
};
|
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.3,
|
version: 0.2,
|
||||||
name: 'RektT5m Parser',
|
name: 'RektT5m Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ var plugin = {
|
|||||||
|
|
||||||
eventParser.Configuration.GameDirectory = 'data';
|
eventParser.Configuration.GameDirectory = 'data';
|
||||||
|
|
||||||
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\x01print\n';
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\x01print';
|
||||||
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
using IW4MAdmin.Plugins.Stats.Models;
|
using IW4MAdmin.Plugins.Stats.Models;
|
||||||
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Cheat
|
namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||||
{
|
{
|
||||||
@ -223,6 +223,11 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
if (weightedSessionAverage > Thresholds.MaxOffset(totalSessionHits) &&
|
if (weightedSessionAverage > Thresholds.MaxOffset(totalSessionHits) &&
|
||||||
totalSessionHits >= (Thresholds.MediumSampleMinKills * 2))
|
totalSessionHits >= (Thresholds.MediumSampleMinKills * 2))
|
||||||
{
|
{
|
||||||
|
Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***");
|
||||||
|
Log.WriteDebug($"Session Average = {weightedSessionAverage}");
|
||||||
|
Log.WriteDebug($"HitCount = {HitCount}");
|
||||||
|
Log.WriteDebug($"ID = {hit.AttackerId}");
|
||||||
|
|
||||||
results.Add(new DetectionPenaltyResult()
|
results.Add(new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
||||||
@ -232,14 +237,18 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Location = hitLoc.Location
|
Location = hitLoc.Location
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.LogDebug("PredictVsReal={realAgainstPredict}", realAgainstPredict);
|
#if DEBUG
|
||||||
|
Log.WriteDebug($"PredictVsReal={realAgainstPredict}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region STRAIN
|
#region STRAIN
|
||||||
double currentStrain = Strain.GetStrain(hit.Distance / 0.0254, hit.ViewAngles, Math.Max(50, LastOffset == 0 ? 50 : (hit.TimeOffset - LastOffset)));
|
double currentStrain = Strain.GetStrain(hit.Distance / 0.0254, hit.ViewAngles, Math.Max(50, LastOffset == 0 ? 50 : (hit.TimeOffset - LastOffset)));
|
||||||
Log.LogDebug("Current Strain: {currentStrain}", currentStrain);
|
#if DEBUG == true
|
||||||
|
Log.WriteDebug($"Current Strain: {currentStrain}");
|
||||||
|
#endif
|
||||||
LastOffset = hit.TimeOffset;
|
LastOffset = hit.TimeOffset;
|
||||||
|
|
||||||
if (currentStrain > ClientStats.MaxStrain)
|
if (currentStrain > ClientStats.MaxStrain)
|
||||||
@ -322,18 +331,18 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
if (!shouldIgnoreDetection)
|
if (!shouldIgnoreDetection)
|
||||||
{
|
{
|
||||||
validButtonHitCount++;
|
validButtonHitCount++;
|
||||||
|
}
|
||||||
|
|
||||||
double lastDiff = hit.TimeOffset - hit.TimeSinceLastAttack;
|
double lastDiff = hit.TimeOffset - hit.TimeSinceLastAttack;
|
||||||
if (validButtonHitCount > 0 && lastDiff <= 0)
|
if (validButtonHitCount > 0 && lastDiff <= 0)
|
||||||
|
{
|
||||||
|
results.Add(new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
results.Add(new DetectionPenaltyResult()
|
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
||||||
{
|
Value = lastDiff,
|
||||||
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
HitCount = HitCount,
|
||||||
Value = lastDiff,
|
Type = DetectionType.Button
|
||||||
HitCount = HitCount,
|
});
|
||||||
Type = DetectionType.Button
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -27,6 +27,12 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
double[] distance = Utilities.AngleStuff(newAngle, LastAngle);
|
double[] distance = Utilities.AngleStuff(newAngle, LastAngle);
|
||||||
LastDistance = distance[0] + distance[1];
|
LastDistance = distance[0] + distance[1];
|
||||||
|
|
||||||
|
#if DEBUG == true
|
||||||
|
Console.WriteLine($"Angle Between = {LastDistance}");
|
||||||
|
Console.WriteLine($"Distance From Target = {killDistance}");
|
||||||
|
Console.WriteLine($"Time Offset = {deltaTime}");
|
||||||
|
Console.WriteLine($"Decay Factor = {decayFactor} ");
|
||||||
|
#endif
|
||||||
// this happens on first kill
|
// this happens on first kill
|
||||||
if ((distance[0] == 0 && distance[1] == 0) ||
|
if ((distance[0] == 0 && distance[1] == 0) ||
|
||||||
deltaTime == 0 ||
|
deltaTime == 0 ||
|
||||||
|
@ -15,7 +15,7 @@ namespace Stats.Config
|
|||||||
Game.IW4, new Dictionary<DetectionType, string[]>
|
Game.IW4, new Dictionary<DetectionType, string[]>
|
||||||
{
|
{
|
||||||
{ DetectionType.Chest, new[] { "m21.+" } },
|
{ DetectionType.Chest, new[] { "m21.+" } },
|
||||||
{ DetectionType.Recoil, new[] { "ranger.*_mp", "model1887.*_mp", ".+shotgun.*_mp", "turret_minigun_mp" } },
|
{ DetectionType.Recoil, new[] { "ranger.*_mp", "model1887.*_mp", ".+shotgun.*_mp" } },
|
||||||
{ DetectionType.Button, new[] { ".*akimbo.*" } }
|
{ DetectionType.Button, new[] { ".*akimbo.*" } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
namespace Stats.Helpers
|
|
||||||
{
|
|
||||||
public class MigrationHelper
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,7 @@ using IW4MAdmin.Plugins.Stats.Models;
|
|||||||
using IW4MAdmin.Plugins.Stats.Web.Dtos;
|
using IW4MAdmin.Plugins.Stats.Web.Dtos;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
@ -14,9 +15,7 @@ using System.Linq;
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using static IW4MAdmin.Plugins.Stats.Cheat.Detection;
|
using static IW4MAdmin.Plugins.Stats.Cheat.Detection;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Helpers
|
namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||||
{
|
{
|
||||||
@ -31,10 +30,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
public static string CLIENT_STATS_KEY = "ClientStats";
|
public static string CLIENT_STATS_KEY = "ClientStats";
|
||||||
public static string CLIENT_DETECTIONS_KEY = "ClientDetections";
|
public static string CLIENT_DETECTIONS_KEY = "ClientDetections";
|
||||||
|
|
||||||
public StatManager(ILogger<StatManager> logger, IManager mgr, IDatabaseContextFactory contextFactory, IConfigurationHandler<StatsConfiguration> configHandler)
|
public StatManager(IManager mgr, IDatabaseContextFactory contextFactory, IConfigurationHandler<StatsConfiguration> configHandler)
|
||||||
{
|
{
|
||||||
_servers = new ConcurrentDictionary<long, ServerStats>();
|
_servers = new ConcurrentDictionary<long, ServerStats>();
|
||||||
_log = logger;
|
_log = mgr.GetLogger(0);
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
_configHandler = configHandler;
|
_configHandler = configHandler;
|
||||||
}
|
}
|
||||||
@ -266,7 +265,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_log.LogError(e, "{message}", Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_ERROR_ADD"]);
|
_log.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_ERROR_ADD"]} - {e.Message}");
|
||||||
|
_log.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
if (!_servers.ContainsKey(serverId))
|
if (!_servers.ContainsKey(serverId))
|
||||||
{
|
{
|
||||||
_log.LogError("[Stats::AddPlayer] Server with id {serverId} could not be found", serverId);
|
_log.WriteError($"[Stats::AddPlayer] Server with id {serverId} could not be found");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +360,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
clientStats.LastScore = pl.Score;
|
clientStats.LastScore = pl.Score;
|
||||||
|
|
||||||
pl.SetAdditionalProperty(CLIENT_DETECTIONS_KEY, new Detection(_log, clientStats));
|
pl.SetAdditionalProperty(CLIENT_DETECTIONS_KEY, new Detection(_log, clientStats));
|
||||||
_log.LogDebug("Added {client} to stats", pl.ToString());
|
pl.CurrentServer.Logger.WriteInfo($"Added {pl} to stats");
|
||||||
}
|
}
|
||||||
|
|
||||||
return clientStats;
|
return clientStats;
|
||||||
@ -368,7 +368,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_log.LogError(ex, "Could not add client to stats {@client}", pl);
|
_log.WriteWarning("Could not add client to stats");
|
||||||
|
_log.WriteDebug(ex.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -381,11 +382,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task RemovePlayer(EFClient pl)
|
public async Task RemovePlayer(EFClient pl)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Removing {client} from stats", pl.ToString());
|
pl.CurrentServer.Logger.WriteInfo($"Removing {pl} from stats");
|
||||||
|
|
||||||
if (pl.CurrentServer == null)
|
if (pl.CurrentServer == null)
|
||||||
{
|
{
|
||||||
_log.LogWarning("Disconnecting client {client} is not on a server", pl.ToString());
|
pl.CurrentServer.Logger.WriteWarning($"Disconnecting client {pl} is not on a server, state is {pl.State}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +407,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_log.LogWarning("Disconnecting client {client} has not been added to stats", pl.ToString());
|
pl.CurrentServer.Logger.WriteWarning($"Disconnecting client {pl} has not been added to stats, state is {pl.State}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,9 +452,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (FormatException ex)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
_log.LogWarning(ex, "Could not parse vector data from hit");
|
_log.WriteError("Could not parse vector data from hit");
|
||||||
|
_log.WriteDebug($"Kill - {killOrigin} Death - {deathOrigin} ViewAngle - {viewAngles} Snapshot - {string.Join(",", snapshotAngles.Select(_a => _a.ToString()))}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,7 +527,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_log.LogError(e, "Could not store client kills");
|
_log.WriteError("Could not store client kills");
|
||||||
|
_log.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@ -580,7 +583,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
catch (TaskCanceledException) { }
|
catch (TaskCanceledException) { }
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_log.LogError(ex, "Could not save hit or anti-cheat info {@attacker} {@victim} {server}", attacker, victim, serverId);
|
_log.WriteError("Could not save hit or AC info");
|
||||||
|
_log.WriteDebug(ex.GetExceptionInfo());
|
||||||
|
_log.WriteDebug($"Attacker: {attacker} Victim: {victim}, ServerId {serverId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@ -628,7 +633,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!detectionTypes[server.EndPoint].Contains(detectionType))
|
if (detectionTypes[server.EndPoint].Contains(detectionType))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -709,6 +714,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
var attackerStats = attacker.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
var attackerStats = attacker.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
||||||
var victimStats = victim.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
var victimStats = victim.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
_log.WriteDebug("Processing standard kill");
|
||||||
|
#endif
|
||||||
// update the total stats
|
// update the total stats
|
||||||
_servers[serverId].ServerStatistics.TotalKills += 1;
|
_servers[serverId].ServerStatistics.TotalKills += 1;
|
||||||
|
|
||||||
@ -746,14 +754,14 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
// fixme: why?
|
// fixme: why?
|
||||||
if (double.IsNaN(victimStats.SPM) || double.IsNaN(victimStats.Skill))
|
if (double.IsNaN(victimStats.SPM) || double.IsNaN(victimStats.Skill))
|
||||||
{
|
{
|
||||||
_log.LogWarning("victim SPM/SKILL {@victimStats}", victimStats);
|
_log.WriteDebug($"[StatManager::AddStandardKill] victim SPM/SKILL {victimStats.SPM} {victimStats.Skill}");
|
||||||
victimStats.SPM = 0.0;
|
victimStats.SPM = 0.0;
|
||||||
victimStats.Skill = 0.0;
|
victimStats.Skill = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (double.IsNaN(attackerStats.SPM) || double.IsNaN(attackerStats.Skill))
|
if (double.IsNaN(attackerStats.SPM) || double.IsNaN(attackerStats.Skill))
|
||||||
{
|
{
|
||||||
_log.LogWarning("attacker SPM/SKILL {@attackerStats}", attackerStats);
|
_log.WriteDebug($"[StatManager::AddStandardKill] attacker SPM/SKILL {victimStats.SPM} {victimStats.Skill}");
|
||||||
attackerStats.SPM = 0.0;
|
attackerStats.SPM = 0.0;
|
||||||
attackerStats.Skill = 0.0;
|
attackerStats.Skill = 0.0;
|
||||||
}
|
}
|
||||||
@ -773,7 +781,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_log.LogWarning(e, "Could not update stat history for {attacker}", attacker.ToString());
|
_log.WriteWarning($"Could not update stat history for {attacker}");
|
||||||
|
_log.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@ -1090,7 +1099,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
if (clientStats.SPM < 0)
|
if (clientStats.SPM < 0)
|
||||||
{
|
{
|
||||||
_log.LogWarning("clientStats SPM < 0 {scoreDifference} {@clientStats}", scoreDifference, clientStats);
|
_log.WriteWarning("[StatManager:UpdateStats] clientStats SPM < 0");
|
||||||
|
_log.WriteDebug($"{scoreDifference}-{clientStats.RoundScore} - {clientStats.LastScore} - {clientStats.SessionScore}");
|
||||||
clientStats.SPM = 0;
|
clientStats.SPM = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1100,7 +1110,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
// fixme: how does this happen?
|
// fixme: how does this happen?
|
||||||
if (double.IsNaN(clientStats.SPM) || double.IsNaN(clientStats.Skill))
|
if (double.IsNaN(clientStats.SPM) || double.IsNaN(clientStats.Skill))
|
||||||
{
|
{
|
||||||
_log.LogWarning("clientStats SPM/Skill NaN {@killInfo}", new {killSPM, KDRWeight, totalPlayTime, SPMAgainstPlayWeight, clientStats, scoreDifference});
|
_log.WriteWarning("[StatManager::UpdateStats] clientStats SPM/Skill NaN");
|
||||||
|
_log.WriteDebug($"{killSPM}-{KDRWeight}-{totalPlayTime}-{SPMAgainstPlayWeight}-{clientStats.SPM}-{clientStats.Skill}-{scoreDifference}");
|
||||||
clientStats.SPM = 0;
|
clientStats.SPM = 0;
|
||||||
clientStats.Skill = 0;
|
clientStats.Skill = 0;
|
||||||
}
|
}
|
||||||
@ -1122,7 +1133,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
if (serverStats == null)
|
if (serverStats == null)
|
||||||
{
|
{
|
||||||
_log.LogDebug("Initializing server stats for {serverId}", serverId);
|
_log.WriteDebug($"Initializing server stats for {serverId}");
|
||||||
// server stats have never been generated before
|
// server stats have never been generated before
|
||||||
serverStats = new EFServerStatistics()
|
serverStats = new EFServerStatistics()
|
||||||
{
|
{
|
||||||
@ -1214,7 +1225,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_log.LogError(e, "There was a problem syncing server stats");
|
_log.WriteError("There was a probably syncing server stats");
|
||||||
|
_log.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
|
@ -14,7 +14,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats
|
namespace IW4MAdmin.Plugins.Stats
|
||||||
{
|
{
|
||||||
@ -29,24 +28,23 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
public static StatManager Manager { get; private set; }
|
public static StatManager Manager { get; private set; }
|
||||||
public static IManager ServerManager;
|
public static IManager ServerManager;
|
||||||
public static IConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
public static IConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
||||||
|
#if DEBUG
|
||||||
|
int scriptDamageCount;
|
||||||
|
int scriptKillCount;
|
||||||
|
#endif
|
||||||
private readonly IDatabaseContextFactory _databaseContextFactory;
|
private readonly IDatabaseContextFactory _databaseContextFactory;
|
||||||
private readonly ITranslationLookup _translationLookup;
|
private readonly ITranslationLookup _translationLookup;
|
||||||
private readonly IMetaService _metaService;
|
private readonly IMetaService _metaService;
|
||||||
private readonly IResourceQueryHelper<ChatSearchQuery, MessageResponse> _chatQueryHelper;
|
private readonly IResourceQueryHelper<ChatSearchQuery, MessageResponse> _chatQueryHelper;
|
||||||
private readonly ILogger<StatManager> _managerLogger;
|
|
||||||
private readonly ILogger<Plugin> _logger;
|
|
||||||
|
|
||||||
public Plugin(ILogger<Plugin> logger, IConfigurationHandlerFactory configurationHandlerFactory, IDatabaseContextFactory databaseContextFactory,
|
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory, IDatabaseContextFactory databaseContextFactory,
|
||||||
ITranslationLookup translationLookup, IMetaService metaService, IResourceQueryHelper<ChatSearchQuery, MessageResponse> chatQueryHelper, ILogger<StatManager> managerLogger)
|
ITranslationLookup translationLookup, IMetaService metaService, IResourceQueryHelper<ChatSearchQuery, MessageResponse> chatQueryHelper)
|
||||||
{
|
{
|
||||||
Config = configurationHandlerFactory.GetConfigurationHandler<StatsConfiguration>("StatsPluginSettings");
|
Config = configurationHandlerFactory.GetConfigurationHandler<StatsConfiguration>("StatsPluginSettings");
|
||||||
_databaseContextFactory = databaseContextFactory;
|
_databaseContextFactory = databaseContextFactory;
|
||||||
_translationLookup = translationLookup;
|
_translationLookup = translationLookup;
|
||||||
_metaService = metaService;
|
_metaService = metaService;
|
||||||
_chatQueryHelper = chatQueryHelper;
|
_chatQueryHelper = chatQueryHelper;
|
||||||
_managerLogger = managerLogger;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnEventAsync(GameEvent E, Server S)
|
public async Task OnEventAsync(GameEvent E, Server S)
|
||||||
@ -104,13 +102,23 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
{
|
{
|
||||||
E.Origin = E.Target;
|
E.Origin = E.Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
scriptKillCount++;
|
||||||
|
S.Logger.WriteInfo($"Start ScriptKill {scriptKillCount}");
|
||||||
|
#endif
|
||||||
|
|
||||||
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(S), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(S), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
S.Logger.WriteInfo($"End ScriptKill {scriptKillCount}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Skipping script kill as it is ignored or data in customcallbacks is outdated/missing");
|
S.Logger.WriteDebug("Skipping script kill as it is ignored or data in customcallbacks is outdated/missing");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Kill:
|
case GameEvent.EventType.Kill:
|
||||||
@ -147,13 +155,22 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
E.Origin = E.Target;
|
E.Origin = E.Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
scriptDamageCount++;
|
||||||
|
S.Logger.WriteInfo($"Start ScriptDamage {scriptDamageCount}");
|
||||||
|
#endif
|
||||||
|
|
||||||
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(S), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(S), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15], killInfo[16], killInfo[17]);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
S.Logger.WriteInfo($"End ScriptDamage {scriptDamageCount}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Skipping script damage as it is ignored or data in customcallbacks is outdated/missing");
|
S.Logger.WriteDebug("Skipping script damage as it is ignored or data in customcallbacks is outdated/missing");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -440,7 +457,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
manager.GetMessageTokens().Add(new MessageToken("MOSTKILLS", mostKills));
|
manager.GetMessageTokens().Add(new MessageToken("MOSTKILLS", mostKills));
|
||||||
|
|
||||||
ServerManager = manager;
|
ServerManager = manager;
|
||||||
Manager = new StatManager(_managerLogger, manager, _databaseContextFactory, Config);
|
Manager = new StatManager(manager, _databaseContextFactory, Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnTickAsync(Server S)
|
public Task OnTickAsync(Server S)
|
||||||
|
@ -13,15 +13,13 @@
|
|||||||
<Copyright>2018</Copyright>
|
<Copyright>2018</Copyright>
|
||||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
<Exec Command="dotnet publish $(ProjectPath) -c $(ConfigurationName) -o $(ProjectDir)..\..\Build\Plugins --no-build --no-restore --no-dependencies" />
|
<Exec Command="dotnet publish $(ProjectPath) -c $(ConfigurationName) -o $(ProjectDir)..\..\Build\Plugins --no-build --no-restore --no-dependencies" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using Stats.Dtos;
|
using Stats.Dtos;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace StatsWeb.API
|
namespace StatsWeb.API
|
||||||
{
|
{
|
||||||
@ -17,7 +16,7 @@ namespace StatsWeb.API
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IResourceQueryHelper<StatsInfoRequest, StatsInfoResult> _statsQueryHelper;
|
private readonly IResourceQueryHelper<StatsInfoRequest, StatsInfoResult> _statsQueryHelper;
|
||||||
|
|
||||||
public StatsController(ILogger<StatsController> logger, IResourceQueryHelper<StatsInfoRequest, StatsInfoResult> statsQueryHelper)
|
public StatsController(ILogger logger, IResourceQueryHelper<StatsInfoRequest, StatsInfoResult> statsQueryHelper)
|
||||||
{
|
{
|
||||||
_statsQueryHelper = statsQueryHelper;
|
_statsQueryHelper = statsQueryHelper;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -57,7 +56,8 @@ namespace StatsWeb.API
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not get client stats for client id {clientId}", clientId);
|
_logger.WriteWarning($"Could not get client stats for client id {clientId}");
|
||||||
|
_logger.WriteDebug(e.GetExceptionInfo());
|
||||||
|
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse
|
return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse
|
||||||
{
|
{
|
||||||
|
@ -10,8 +10,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace StatsWeb
|
namespace StatsWeb
|
||||||
{
|
{
|
||||||
@ -25,7 +23,7 @@ namespace StatsWeb
|
|||||||
private readonly ApplicationConfiguration _appConfig;
|
private readonly ApplicationConfiguration _appConfig;
|
||||||
private List<EFServer> serverCache;
|
private List<EFServer> serverCache;
|
||||||
|
|
||||||
public ChatResourceQueryHelper(ILogger<ChatResourceQueryHelper> logger, IDatabaseContextFactory contextFactory, ApplicationConfiguration appConfig)
|
public ChatResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory, ApplicationConfiguration appConfig)
|
||||||
{
|
{
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -10,11 +10,8 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using Stats.Dtos;
|
using Stats.Dtos;
|
||||||
using StatsWeb.Extensions;
|
using StatsWeb.Extensions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
||||||
{
|
{
|
||||||
@ -25,7 +22,7 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
|||||||
private readonly IResourceQueryHelper<ChatSearchQuery, MessageResponse> _chatResourceQueryHelper;
|
private readonly IResourceQueryHelper<ChatSearchQuery, MessageResponse> _chatResourceQueryHelper;
|
||||||
private readonly ITranslationLookup _translationLookup;
|
private readonly ITranslationLookup _translationLookup;
|
||||||
|
|
||||||
public StatsController(ILogger<StatsController> logger, IManager manager, IResourceQueryHelper<ChatSearchQuery, MessageResponse> resourceQueryHelper,
|
public StatsController(ILogger logger, IManager manager, IResourceQueryHelper<ChatSearchQuery, MessageResponse> resourceQueryHelper,
|
||||||
ITranslationLookup translationLookup) : base(manager)
|
ITranslationLookup translationLookup) : base(manager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -89,7 +86,7 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
|||||||
SentAfter = whenLower
|
SentAfter = whenLower
|
||||||
});
|
});
|
||||||
|
|
||||||
return View("_MessageContext", messages.Results.ToList());
|
return View("_MessageContext", messages.Results);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("Message/Find")]
|
[HttpGet("Message/Find")]
|
||||||
@ -111,13 +108,15 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
|||||||
|
|
||||||
catch (ArgumentException e)
|
catch (ArgumentException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not parse chat message search query {query}", query);
|
_logger.WriteWarning($"Could not parse chat message search query - {query}");
|
||||||
|
_logger.WriteDebug(e.GetExceptionInfo());
|
||||||
ViewBag.Error = e;
|
ViewBag.Error = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (FormatException e)
|
catch (FormatException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not parse chat message search query filter format {query}", query);
|
_logger.WriteWarning($"Could not parse chat message search query filter format - {query}");
|
||||||
|
_logger.WriteDebug(e.GetExceptionInfo());
|
||||||
ViewBag.Error = e;
|
ViewBag.Error = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,13 +136,15 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
|||||||
|
|
||||||
catch (ArgumentException e)
|
catch (ArgumentException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not parse chat message search query {query}", query);
|
_logger.WriteWarning($"Could not parse chat message search query - {query}");
|
||||||
|
_logger.WriteDebug(e.GetExceptionInfo());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (FormatException e)
|
catch (FormatException e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Could not parse chat message search query filter format {query}", query);
|
_logger.WriteWarning($"Could not parse chat message search query filter format - {query}");
|
||||||
|
_logger.WriteDebug(e.GetExceptionInfo());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,13 +189,13 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
|||||||
// we want to show anything related to the automated offense
|
// we want to show anything related to the automated offense
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return View("_MessageContext", new List<MessageResponse>
|
return View("_MessageContext", new[]
|
||||||
{
|
{
|
||||||
new MessageResponse()
|
new ChatInfo()
|
||||||
{
|
{
|
||||||
ClientId = penalty.OffenderId,
|
ClientId = penalty.OffenderId,
|
||||||
Message = penalty.AutomatedOffense,
|
Message = penalty.AutomatedOffense,
|
||||||
When = penalty.When
|
Time = penalty.When
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -28,7 +28,7 @@
|
|||||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
<Exec Command="dotnet publish $(ProjectPath) -c $(ConfigurationName) -o $(ProjectDir)..\..\..\BUILD\Plugins --no-build --no-restore --no-dependencies" />
|
<Exec Command="dotnet publish $(ProjectPath) -c $(ConfigurationName) -o $(ProjectDir)..\..\..\BUILD\Plugins --no-build --no-restore --no-dependencies" />
|
||||||
</Target>
|
</Target>
|
||||||
|
@ -6,37 +6,21 @@
|
|||||||
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))
|
||||||
{
|
|
||||||
return "0_no-place/menu_div_no_place.png";
|
return "0_no-place/menu_div_no_place.png";
|
||||||
}
|
|
||||||
if (elo >= getDeviation(0.125) && elo < getDeviation(0.625))
|
if (elo >= getDeviation(0.125) && elo < getDeviation(0.625))
|
||||||
{
|
|
||||||
return "1_iron/menu_div_iron_sub03.png";
|
return "1_iron/menu_div_iron_sub03.png";
|
||||||
}
|
|
||||||
if (elo >= getDeviation(0.625) && elo < getDeviation(1.0))
|
if (elo >= getDeviation(0.625) && elo < getDeviation(1.0))
|
||||||
{
|
|
||||||
return "2_bronze/menu_div_bronze_sub03.png";
|
return "2_bronze/menu_div_bronze_sub03.png";
|
||||||
}
|
|
||||||
if (elo >= getDeviation(1.0) && elo < getDeviation(1.25))
|
if (elo >= getDeviation(1.0) && elo < getDeviation(1.25))
|
||||||
{
|
|
||||||
return "3_silver/menu_div_silver_sub03.png";
|
return "3_silver/menu_div_silver_sub03.png";
|
||||||
}
|
|
||||||
if (elo >= getDeviation(1.25) && elo < getDeviation(1.5))
|
if (elo >= getDeviation(1.25) && elo < getDeviation(1.5))
|
||||||
{
|
|
||||||
return "4_gold/menu_div_gold_sub03.png";
|
return "4_gold/menu_div_gold_sub03.png";
|
||||||
}
|
|
||||||
if (elo >= getDeviation(1.5) && elo < getDeviation(1.75))
|
if (elo >= getDeviation(1.5) && elo < getDeviation(1.75))
|
||||||
{
|
|
||||||
return "5_platinum/menu_div_platinum_sub03.png";
|
return "5_platinum/menu_div_platinum_sub03.png";
|
||||||
}
|
|
||||||
if (elo >= getDeviation(1.75) && elo < getDeviation(2.0))
|
if (elo >= getDeviation(1.75) && elo < getDeviation(2.0))
|
||||||
{
|
|
||||||
return "6_semipro/menu_div_semipro_sub03.png";
|
return "6_semipro/menu_div_semipro_sub03.png";
|
||||||
}
|
|
||||||
if (elo >= getDeviation(2.0))
|
if (elo >= getDeviation(2.0))
|
||||||
{
|
|
||||||
return "7_pro/menu_div_pro_sub03.png";
|
return "7_pro/menu_div_pro_sub03.png";
|
||||||
}
|
|
||||||
|
|
||||||
return "0_no-place/menu_div_no_place.png";
|
return "0_no-place/menu_div_no_place.png";
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@using SharedLibraryCore.Dtos.Meta.Responses
|
@using SharedLibraryCore.Dtos.Meta.Responses
|
||||||
@model IList<MessageResponse>
|
@model IEnumerable<MessageResponse>
|
||||||
@{
|
@{
|
||||||
Layout = null;
|
Layout = null;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2020.11.11.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
7
RunPublishPre.cmd
Normal file
7
RunPublishPre.cmd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
dotnet publish WebfrontCore/WebfrontCore.csproj -c Prerelease -f netcoreapp3.0 --force -o X:\IW4MAdmin\Publish\WindowsPrerelease /p:PublishProfile=Prerelease
|
||||||
|
dotnet publish Application/Application.csproj -c Prerelease -f netcoreapp3.0 --force -o X:\IW4MAdmin\Publish\WindowsPrerelease /p:PublishProfile=Prerelease
|
||||||
|
dotnet publish GameLogServer/GameLogServer.pyproj -c Release -f netcoreapp3.0 --force -o X:\IW4MAdmin\Publish\WindowsPrerelease\GameLogServer
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat"
|
||||||
|
msbuild GameLogServer/GameLogServer.pyproj /p:PublishProfile=PreRelease /p:DeployOnBuild=true /p:PublishProfileRootFolder=X:\IW4MAdmin\GameLogServer\
|
||||||
|
cd "X:\IW4MAdmin\DEPLOY\"
|
||||||
|
PowerShell ".\upload_prerelease.ps1"
|
7
RunPublishRelease.cmd
Normal file
7
RunPublishRelease.cmd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
dotnet publish WebfrontCore/WebfrontCore.csproj -c Release -f netcoreapp3.0 --force -o X:\IW4MAdmin\Publish\Windows /p:PublishProfile=sTABLE
|
||||||
|
dotnet publish Application/Application.csproj -c Release -f netcoreapp3.0 --force -o X:\IW4MAdmin\Publish\Windows /p:PublishProfile=Stable
|
||||||
|
dotnet publish GameLogServer/GameLogServer.pyproj -c Release -f netcoreapp3.0 --force -o X:\IW4MAdmin\Publish\WindowsPrerelease\GameLogServer
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat"
|
||||||
|
msbuild GameLogServer/GameLogServer.pyproj /p:PublishProfile=Stable /p:DeployOnBuild=true /p:PublishProfileRootFolder=X:\IW4MAdmin\GameLogServer\
|
||||||
|
cd "X:\IW4MAdmin\DEPLOY\"
|
||||||
|
PowerShell ".\upload_release.ps1"
|
@ -6,7 +6,6 @@ using SharedLibraryCore.Configuration;
|
|||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore
|
namespace SharedLibraryCore
|
||||||
{
|
{
|
||||||
|
@ -12,8 +12,6 @@ using System.Security.Cryptography;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Commands
|
namespace SharedLibraryCore.Commands
|
||||||
@ -241,42 +239,6 @@ namespace SharedLibraryCore.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prints out a message to all clients on all servers
|
|
||||||
/// </summary>
|
|
||||||
public class SayAllCommand : Command
|
|
||||||
{
|
|
||||||
public SayAllCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
|
|
||||||
{
|
|
||||||
Name = "sayall";
|
|
||||||
Description = _translationLookup["COMMANDS_SAY_ALL_DESC"];
|
|
||||||
Alias = "sa";
|
|
||||||
Permission = Permission.Moderator;
|
|
||||||
RequiresTarget = false;
|
|
||||||
Arguments = new[]
|
|
||||||
{
|
|
||||||
new CommandArgument()
|
|
||||||
{
|
|
||||||
Name = _translationLookup["COMMANDS_ARGS_MESSAGE"],
|
|
||||||
Required = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Task ExecuteAsync(GameEvent E)
|
|
||||||
{
|
|
||||||
string message = _translationLookup["COMMANDS_SAY_ALL_MESSAGE_FORMAT"].FormatExt(E.Origin.Name, E.Data);
|
|
||||||
|
|
||||||
foreach (var server in E.Owner.Manager.GetServers())
|
|
||||||
{
|
|
||||||
server.Broadcast(message, E.Origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
E.Origin.Tell(_translationLookup["COMMANDS_SAY_SUCCESS"]);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Temporarily bans a client
|
/// Temporarily bans a client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -634,11 +596,11 @@ namespace SharedLibraryCore.Commands
|
|||||||
|
|
||||||
public override async Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
_ = !E.Origin.Masked ?
|
var _ = !E.Origin.Masked ?
|
||||||
E.Owner.Broadcast($"{_translationLookup["COMMANDS_MAPROTATE"]} [^5{E.Origin.Name}^7]", E.Origin) :
|
E.Owner.Broadcast($"{_translationLookup["COMMANDS_MAPROTATE"]} [^5{E.Origin.Name}^7]", E.Origin) :
|
||||||
E.Owner.Broadcast(_translationLookup["COMMANDS_MAPROTATE"], E.Origin);
|
E.Owner.Broadcast(_translationLookup["COMMANDS_MAPROTATE"], E.Origin);
|
||||||
|
|
||||||
await Task.Delay(E.Owner.Manager.GetApplicationSettings().Configuration().MapChangeDelaySeconds * 1000);
|
await Task.Delay(5000);
|
||||||
await E.Owner.ExecuteCommandAsync("map_rotate");
|
await E.Owner.ExecuteCommandAsync("map_rotate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -648,7 +610,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SetLevelCommand : Command
|
public class SetLevelCommand : Command
|
||||||
{
|
{
|
||||||
public SetLevelCommand(CommandConfiguration config, ITranslationLookup translationLookup, ILogger<SetLevelCommand> logger) : base(config, translationLookup)
|
public SetLevelCommand(CommandConfiguration config, ITranslationLookup translationLookup, ILogger logger) : base(config, translationLookup)
|
||||||
{
|
{
|
||||||
Name = "setlevel";
|
Name = "setlevel";
|
||||||
Description = _translationLookup["COMMANDS_SETLEVEL_DESC"];
|
Description = _translationLookup["COMMANDS_SETLEVEL_DESC"];
|
||||||
@ -729,16 +691,13 @@ namespace SharedLibraryCore.Commands
|
|||||||
gameEvent.Owner.Manager.GetActiveClients()
|
gameEvent.Owner.Manager.GetActiveClients()
|
||||||
.FirstOrDefault(c => c.ClientId == targetClient?.ClientId) ?? targetClient : targetClient;
|
.FirstOrDefault(c => c.ClientId == targetClient?.ClientId) ?? targetClient : targetClient;
|
||||||
|
|
||||||
logger.LogDebug("Beginning set level of client {origin} to {newPermission}", gameEvent.Origin.ToString(), newPerm);
|
logger.WriteInfo($"Beginning set level of client {gameEvent.Origin} to {newPerm}");
|
||||||
|
|
||||||
var result = await targetClient.SetLevel(newPerm, gameEvent.Origin).WaitAsync(Utilities.DefaultCommandTimeout, gameEvent.Owner.Manager.CancellationToken);
|
var result = await targetClient.SetLevel(newPerm, gameEvent.Origin).WaitAsync(Utilities.DefaultCommandTimeout, gameEvent.Owner.Manager.CancellationToken);
|
||||||
|
|
||||||
if (result.Failed)
|
if (result.Failed)
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", gameEvent.Origin.CurrentServer?.ToString()))
|
logger.WriteInfo($"Failed to set level of client {gameEvent.Origin}");
|
||||||
{
|
|
||||||
logger.LogWarning("Failed to set level of client {origin}", gameEvent.Origin.ToString());
|
|
||||||
}
|
|
||||||
gameEvent.Origin.Tell(_translationLookup["SERVER_ERROR_COMMAND_INGAME"]);
|
gameEvent.Origin.Tell(_translationLookup["SERVER_ERROR_COMMAND_INGAME"]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -869,18 +828,22 @@ namespace SharedLibraryCore.Commands
|
|||||||
|
|
||||||
public override async Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
string newMap = E.Data.Trim();
|
string newMap = E.Data.Trim().ToLower();
|
||||||
int delay = E.Owner.Manager.GetApplicationSettings().Configuration().MapChangeDelaySeconds * 1000;
|
foreach (Map m in E.Owner.Maps)
|
||||||
|
{
|
||||||
|
if (m.Name.ToLower() == newMap || m.Alias.ToLower() == newMap)
|
||||||
|
{
|
||||||
|
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_SUCCESS"].FormatExt(m.Alias));
|
||||||
|
await Task.Delay((int)(Utilities.DefaultCommandTimeout.TotalMilliseconds / 2.0));
|
||||||
|
await E.Owner.LoadMap(m.Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var foundMap = E.Owner.Maps.FirstOrDefault(_map => _map.Name.Equals(newMap, StringComparison.InvariantCultureIgnoreCase) ||
|
// todo: this can be moved into a single statement
|
||||||
_map.Alias.Equals(newMap, StringComparison.InvariantCultureIgnoreCase));
|
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_UKN"].FormatExt(newMap));
|
||||||
|
await Task.Delay(5000);
|
||||||
_ = foundMap == null ?
|
await E.Owner.LoadMap(newMap);
|
||||||
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_UKN"].FormatExt(newMap)) :
|
|
||||||
E.Owner.Broadcast(_translationLookup["COMMANDS_MAP_SUCCESS"].FormatExt(foundMap.Alias));
|
|
||||||
|
|
||||||
await Task.Delay(delay);
|
|
||||||
await E.Owner.LoadMap(foundMap?.Name ?? newMap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1566,7 +1529,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SetGravatarCommand : Command
|
public class SetGravatarCommand : Command
|
||||||
{
|
{
|
||||||
private readonly IMetaService _metaService;
|
private readonly IMetaService _metaService;
|
||||||
|
|
||||||
public SetGravatarCommand(CommandConfiguration config, ITranslationLookup translationLookup, IMetaService metaService) : base(config, translationLookup)
|
public SetGravatarCommand(CommandConfiguration config, ITranslationLookup translationLookup, IMetaService metaService) : base(config, translationLookup)
|
||||||
{
|
{
|
||||||
|
@ -91,16 +91,12 @@ namespace SharedLibraryCore.Configuration
|
|||||||
public string[] GlobalRules { get; set; } = new string[0];
|
public string[] GlobalRules { get; set; } = new string[0];
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_DISALLOWED_NAMES")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_DISALLOWED_NAMES")]
|
||||||
public string[] DisallowedClientNames { get; set; } = new string[0];
|
public string[] DisallowedClientNames { get; set; } = new string[0];
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_MAP_CHANGE_DELAY")]
|
|
||||||
public int MapChangeDelaySeconds { get; set; } = 5;
|
|
||||||
[UIHint("ServerConfiguration")]
|
[UIHint("ServerConfiguration")]
|
||||||
public ServerConfiguration[] Servers { get; set; }
|
public ServerConfiguration[] Servers { get; set; }
|
||||||
|
|
||||||
[ConfigurationIgnore]
|
[ConfigurationIgnore]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
[ConfigurationIgnore]
|
[ConfigurationIgnore]
|
||||||
public string SubscriptionId { get; set; }
|
|
||||||
[ConfigurationIgnore]
|
|
||||||
public MapConfiguration[] Maps { get; set; }
|
public MapConfiguration[] Maps { get; set; }
|
||||||
[ConfigurationIgnore]
|
[ConfigurationIgnore]
|
||||||
public QuickMessageConfiguration[] QuickMessages { get; set; }
|
public QuickMessageConfiguration[] QuickMessages { get; set; }
|
||||||
|
@ -205,18 +205,7 @@ namespace SharedLibraryCore.Database
|
|||||||
pluginDir = Path.Join(Utilities.OperatingDirectory, "..", "..", "..", "..", "BUILD", "Plugins");
|
pluginDir = Path.Join(Utilities.OperatingDirectory, "..", "..", "..", "..", "BUILD", "Plugins");
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<string> directoryFiles = Enumerable.Empty<string>();
|
IEnumerable<string> directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.EndsWith(".dll"));
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.EndsWith(".dll"));
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (DirectoryNotFoundException)
|
|
||||||
{
|
|
||||||
// this is just an ugly thing for unit testing
|
|
||||||
directoryFiles = Directory.GetFiles(@"X:\IW4MAdmin\Tests\ApplicationTests\bin\Debug\netcoreapp3.1").Where(f => f.EndsWith("dll"));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string dllPath in directoryFiles)
|
foreach (string dllPath in directoryFiles)
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,6 @@ using SharedLibraryCore.Events;
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore
|
namespace SharedLibraryCore
|
||||||
{
|
{
|
||||||
@ -256,6 +254,9 @@ namespace SharedLibraryCore
|
|||||||
public void Complete()
|
public void Complete()
|
||||||
{
|
{
|
||||||
_eventFinishedWaiter.Set();
|
_eventFinishedWaiter.Set();
|
||||||
|
#if DEBUG
|
||||||
|
Owner?.Logger.WriteDebug($"Completed internal for event {Id}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -265,7 +266,11 @@ namespace SharedLibraryCore
|
|||||||
public async Task<GameEvent> WaitAsync(TimeSpan timeSpan, CancellationToken token)
|
public async Task<GameEvent> WaitAsync(TimeSpan timeSpan, CancellationToken token)
|
||||||
{
|
{
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
Utilities.DefaultLogger.LogDebug("Begin wait for event {Id}", Id);
|
|
||||||
|
#if DEBUG
|
||||||
|
Owner?.Logger.WriteDebug($"Begin wait for event {Id}");
|
||||||
|
#endif
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
processed = await Task.Run(() => _eventFinishedWaiter.WaitOne(timeSpan), token);
|
processed = await Task.Run(() => _eventFinishedWaiter.WaitOne(timeSpan), token);
|
||||||
@ -278,12 +283,14 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
if (!processed)
|
if (!processed)
|
||||||
{
|
{
|
||||||
using(LogContext.PushProperty("Server", Owner?.ToString()))
|
Owner?.Logger.WriteError("Waiting for event to complete timed out");
|
||||||
{
|
Owner?.Logger.WriteDebug($"{Id}, {Type}, {Data}, {Extra}, {FailReason.ToString()}, {Message}, {Origin}, {Target}");
|
||||||
Utilities.DefaultLogger.LogError("Waiting for event to complete timed out {@eventData}", new { Event = this, Message, Origin = Origin.ToString(), Target = Target.ToString()});
|
#if DEBUG
|
||||||
}
|
//throw new Exception();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// this lets us know if the the action timed out
|
// this lets us know if the the action timed out
|
||||||
FailReason = FailReason == EventFailReason.None && !processed ? EventFailReason.Timeout : FailReason;
|
FailReason = FailReason == EventFailReason.None && !processed ? EventFailReason.Timeout : FailReason;
|
||||||
return this;
|
return this;
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Exceptions
|
|
||||||
{
|
|
||||||
public class RConException : Exception
|
|
||||||
{
|
|
||||||
public RConException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
[Obsolete]
|
|
||||||
public interface ILogger
|
public interface ILogger
|
||||||
{
|
{
|
||||||
void WriteVerbose(string msg);
|
void WriteVerbose(string msg);
|
||||||
|
@ -6,7 +6,6 @@ using SharedLibraryCore.Database.Models;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
@ -16,7 +15,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
Task Start();
|
Task Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
void Restart();
|
void Restart();
|
||||||
[Obsolete]
|
|
||||||
ILogger GetLogger(long serverId);
|
ILogger GetLogger(long serverId);
|
||||||
IList<Server> GetServers();
|
IList<Server> GetServers();
|
||||||
IList<IManagerCommand> GetCommands();
|
IList<IManagerCommand> GetCommands();
|
||||||
|
@ -17,9 +17,9 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "");
|
Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// sets the rcon parser
|
/// sets the rcon parser configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config">parser</param>
|
/// <param name="config">parser config</param>
|
||||||
void SetConfiguration(IRConParser config);
|
void SetConfiguration(IRConParserConfiguration config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
@ -83,12 +82,5 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <param name="dvarName">dvar key name</param>
|
/// <param name="dvarName">dvar key name</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
T GetDefaultDvarValue<T>(string dvarName);
|
T GetDefaultDvarValue<T>(string dvarName);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// determines the amount of time to wait for the command to respond
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="command">name of command being executed</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
TimeSpan OverrideTimeoutForCommand(string command);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
|
||||||
{
|
|
||||||
public interface IRemoteAssemblyHandler
|
|
||||||
{
|
|
||||||
IEnumerable<Assembly> DecryptAssemblies(string[] encryptedAssemblies);
|
|
||||||
IEnumerable<string> DecryptScripts(string[] encryptedScripts);
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,8 +8,6 @@ using System.Text.Json.Serialization;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Database.Models
|
namespace SharedLibraryCore.Database.Models
|
||||||
{
|
{
|
||||||
@ -91,7 +89,6 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
SetAdditionalProperty("_reportCount", 0);
|
SetAdditionalProperty("_reportCount", 0);
|
||||||
ReceivedPenalties = new List<EFPenalty>();
|
ReceivedPenalties = new List<EFPenalty>();
|
||||||
_processingEvent = new SemaphoreSlim(1, 1);
|
_processingEvent = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~EFClient()
|
~EFClient()
|
||||||
@ -478,42 +475,39 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
{
|
{
|
||||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
|
|
||||||
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
if (string.IsNullOrWhiteSpace(Name) || CleanedName.Replace(" ", "").Length < 3)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(Name) || CleanedName.Replace(" ", "").Length < 3)
|
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is too short");
|
||||||
{
|
Kick(loc["SERVER_KICK_MINNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
||||||
Utilities.DefaultLogger.LogInformation("Kicking {client} because their name is too short", ToString());
|
return false;
|
||||||
Kick(loc["SERVER_KICK_MINNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentServer.Manager.GetApplicationSettings().Configuration()
|
if (CurrentServer.Manager.GetApplicationSettings().Configuration()
|
||||||
.DisallowedClientNames
|
.DisallowedClientNames
|
||||||
?.Any(_name => Regex.IsMatch(Name, _name)) ?? false)
|
?.Any(_name => Regex.IsMatch(Name, _name)) ?? false)
|
||||||
{
|
{
|
||||||
Utilities.DefaultLogger.LogInformation("Kicking {client} because their name is not allowed", ToString());
|
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is not allowed");
|
||||||
Kick(loc["SERVER_KICK_GENERICNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
Kick(loc["SERVER_KICK_GENERICNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Name.Where(c => char.IsControl(c)).Count() > 0)
|
if (Name.Where(c => char.IsControl(c)).Count() > 0)
|
||||||
{
|
{
|
||||||
Utilities.DefaultLogger.LogInformation("Kicking {client} because their name contains control characters", ToString());
|
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name contains control characters");
|
||||||
Kick(loc["SERVER_KICK_CONTROLCHARS"], Utilities.IW4MAdminClient(CurrentServer));
|
Kick(loc["SERVER_KICK_CONTROLCHARS"], Utilities.IW4MAdminClient(CurrentServer));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reserved slots stuff
|
// reserved slots stuff
|
||||||
// todo: bots don't seem to honor party_maxplayers/sv_maxclients
|
// todo: bots don't seem to honor party_maxplayers/sv_maxclients
|
||||||
if (CurrentServer.MaxClients - (CurrentServer.GetClientsAsList().Count(_client => !_client.IsPrivileged() && !_client.IsBot)) < CurrentServer.ServerConfig.ReservedSlotNumber &&
|
if (CurrentServer.MaxClients - (CurrentServer.GetClientsAsList().Count(_client => !_client.IsPrivileged() && !_client.IsBot)) < CurrentServer.ServerConfig.ReservedSlotNumber &&
|
||||||
!this.IsPrivileged() &&
|
!this.IsPrivileged() &&
|
||||||
CurrentServer.GetClientsAsList().Count <= CurrentServer.MaxClients &&
|
CurrentServer.GetClientsAsList().Count <= CurrentServer.MaxClients &&
|
||||||
CurrentServer.MaxClients != 0)
|
CurrentServer.MaxClients != 0)
|
||||||
{
|
{
|
||||||
Utilities.DefaultLogger.LogInformation("Kicking {client} their spot is reserved", ToString());
|
CurrentServer.Logger.WriteDebug($"Kicking {this} their spot is reserved");
|
||||||
Kick(loc["SERVER_KICK_SLOT_IS_RESERVED"], Utilities.IW4MAdminClient(CurrentServer));
|
Kick(loc["SERVER_KICK_SLOT_IS_RESERVED"], Utilities.IW4MAdminClient(CurrentServer));
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -521,151 +515,126 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
public async Task OnDisconnect()
|
public async Task OnDisconnect()
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
TotalConnectionTime += ConnectionLength;
|
||||||
|
LastConnection = DateTime.UtcNow;
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
TotalConnectionTime += ConnectionLength;
|
await CurrentServer.Manager.GetClientService().Update(this);
|
||||||
LastConnection = DateTime.UtcNow;
|
}
|
||||||
|
|
||||||
Utilities.DefaultLogger.LogInformation("Client {client} is leaving the game", ToString());
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
CurrentServer.Logger.WriteWarning($"Could not update disconnected player {this}");
|
||||||
|
CurrentServer.Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
try
|
finally
|
||||||
{
|
{
|
||||||
await CurrentServer.Manager.GetClientService().Update(this);
|
State = ClientState.Unknown;
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Utilities.DefaultLogger.LogError(e, "Could not update disconnected client {client}",
|
|
||||||
ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
State = ClientState.Unknown;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnJoin(int? ipAddress)
|
public async Task OnJoin(int? ipAddress)
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
CurrentServer.Logger.WriteDebug($"Start join for {this}::{ipAddress}::{Level.ToString()}");
|
||||||
|
|
||||||
|
if (ipAddress != null)
|
||||||
{
|
{
|
||||||
Utilities.DefaultLogger.LogInformation("Client {client} is joining the game from {source}", ToString(), ipAddress.HasValue ? "Status" : "Log");
|
IPAddress = ipAddress;
|
||||||
|
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
||||||
|
CurrentServer.Logger.WriteDebug($"Updated alias for {this}");
|
||||||
|
await CurrentServer.Manager.GetClientService().Update(this);
|
||||||
|
CurrentServer.Logger.WriteDebug($"Updated client for {this}");
|
||||||
|
|
||||||
if (ipAddress != null)
|
bool canConnect = await CanConnect(ipAddress);
|
||||||
|
|
||||||
|
if (!canConnect)
|
||||||
{
|
{
|
||||||
IPAddress = ipAddress;
|
CurrentServer.Logger.WriteDebug($"Client {this} is not allowed to join the server");
|
||||||
Utilities.DefaultLogger.LogInformation("Received ip from client {client}", ToString());
|
|
||||||
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
|
||||||
await CurrentServer.Manager.GetClientService().Update(this);
|
|
||||||
|
|
||||||
bool canConnect = await CanConnect(ipAddress);
|
|
||||||
|
|
||||||
if (!canConnect)
|
|
||||||
{
|
|
||||||
Utilities.DefaultLogger.LogInformation("Client {client} is not allowed to join the server",
|
|
||||||
ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Utilities.DefaultLogger.LogDebug("Creating join event for {client}", ToString());
|
|
||||||
var e = new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.Join,
|
|
||||||
Origin = this,
|
|
||||||
Target = this,
|
|
||||||
Owner = CurrentServer,
|
|
||||||
};
|
|
||||||
|
|
||||||
CurrentServer.Manager.AddEvent(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Utilities.DefaultLogger.LogInformation("Waiting to receive ip from client {client}", ToString());
|
CurrentServer.Logger.WriteDebug($"Creating join event for {this}");
|
||||||
}
|
var e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Join,
|
||||||
|
Origin = this,
|
||||||
|
Target = this,
|
||||||
|
Owner = CurrentServer,
|
||||||
|
};
|
||||||
|
|
||||||
Utilities.DefaultLogger.LogDebug("OnJoin finished for {client}", ToString());
|
CurrentServer.Manager.AddEvent(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentServer.Logger.WriteDebug($"Client {this} does not have an IP yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentServer.Logger.WriteDebug($"OnJoin finished for {this}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> CanConnect(int? ipAddress)
|
public async Task<bool> CanConnect(int? ipAddress)
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
|
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
|
||||||
|
|
||||||
|
bool isAbleToConnectSimple = IsAbleToConnectSimple();
|
||||||
|
|
||||||
|
if (!isAbleToConnectSimple)
|
||||||
{
|
{
|
||||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
return false;
|
||||||
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
|
}
|
||||||
|
|
||||||
bool isAbleToConnectSimple = IsAbleToConnectSimple();
|
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
|
||||||
|
var activePenalties = await CurrentServer.Manager.GetPenaltyService().GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
||||||
|
var banPenalty = activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Ban);
|
||||||
|
var tempbanPenalty = activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.TempBan);
|
||||||
|
var flagPenalty = activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Flag);
|
||||||
|
|
||||||
if (!isAbleToConnectSimple)
|
// we want to kick them if any account is banned
|
||||||
|
if (banPenalty != null)
|
||||||
|
{
|
||||||
|
if (Level == Permission.Banned)
|
||||||
{
|
{
|
||||||
|
CurrentServer.Logger.WriteDebug($"Kicking {this} because they are banned");
|
||||||
|
Kick(loc["SERVER_BAN_PREV"].FormatExt(banPenalty?.Offense), autoKickClient);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
|
else
|
||||||
var activePenalties = await CurrentServer.Manager.GetPenaltyService()
|
|
||||||
.GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
|
||||||
var banPenalty = activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Ban);
|
|
||||||
var tempbanPenalty =
|
|
||||||
activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.TempBan);
|
|
||||||
var flagPenalty =
|
|
||||||
activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Flag);
|
|
||||||
|
|
||||||
// we want to kick them if any account is banned
|
|
||||||
if (banPenalty != null)
|
|
||||||
{
|
{
|
||||||
if (Level == Permission.Banned)
|
CurrentServer.Logger.WriteDebug($"Client {this} is banned, but using a new GUID, we we're updating their level and kicking them");
|
||||||
{
|
await SetLevel(Permission.Banned, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout, CurrentServer.Manager.CancellationToken);
|
||||||
Utilities.DefaultLogger.LogInformation("Kicking {client} because they are banned", ToString());
|
Kick(loc["SERVER_BAN_PREV"].FormatExt(banPenalty?.Offense), autoKickClient);
|
||||||
Kick(loc["SERVER_BAN_PREV"].FormatExt(banPenalty?.Offense), autoKickClient);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Utilities.DefaultLogger.LogInformation(
|
|
||||||
"Client {client} is banned, but using a new GUID, we we're updating their level and kicking them",
|
|
||||||
ToString());
|
|
||||||
await SetLevel(Permission.Banned, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout,
|
|
||||||
CurrentServer.Manager.CancellationToken);
|
|
||||||
Kick(loc["SERVER_BAN_PREV"].FormatExt(banPenalty?.Offense), autoKickClient);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we want to kick them if any account is tempbanned
|
|
||||||
if (tempbanPenalty != null)
|
|
||||||
{
|
|
||||||
Utilities.DefaultLogger.LogInformation("Kicking {client} because their GUID is temporarily banned",
|
|
||||||
ToString());
|
|
||||||
Kick(
|
|
||||||
$"{loc["SERVER_TB_REMAIN"]} ({(tempbanPenalty.Expires.Value - DateTime.UtcNow).HumanizeForCurrentCulture()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})",
|
|
||||||
autoKickClient);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if we found a flag, we need to make sure all the accounts are flagged
|
// we want to kick them if any account is tempbanned
|
||||||
if (flagPenalty != null && Level != Permission.Flagged)
|
if (tempbanPenalty != null)
|
||||||
{
|
{
|
||||||
Utilities.DefaultLogger.LogInformation(
|
CurrentServer.Logger.WriteDebug($"Kicking {this} because their GUID is temporarily banned");
|
||||||
"Flagged client {client} joining with new GUID, so we are changing their level to flagged",
|
Kick($"{loc["SERVER_TB_REMAIN"]} ({(tempbanPenalty.Expires.Value - DateTime.UtcNow).HumanizeForCurrentCulture()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
|
||||||
ToString());
|
return false;
|
||||||
await SetLevel(Permission.Flagged, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout,
|
}
|
||||||
CurrentServer.Manager.CancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove their auto flag
|
// if we found a flag, we need to make sure all the accounts are flagged
|
||||||
if (Level == Permission.Flagged &&
|
if (flagPenalty != null && Level != Permission.Flagged)
|
||||||
!activePenalties.Any(_penalty => _penalty.Type == EFPenalty.PenaltyType.Flag))
|
{
|
||||||
{
|
CurrentServer.Logger.WriteDebug($"Flagged client {this} joining with new GUID, so we are changing their level to flagged");
|
||||||
// remove their auto flag status after a week
|
await SetLevel(Permission.Flagged, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout, CurrentServer.Manager.CancellationToken);
|
||||||
Utilities.DefaultLogger.LogInformation("Unflagging {client} because the auto flag time has expired",
|
}
|
||||||
ToString());
|
|
||||||
Unflag(Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTOFLAG_UNFLAG"], autoKickClient);
|
// remove their auto flag
|
||||||
}
|
if (Level == Permission.Flagged && !activePenalties.Any(_penalty => _penalty.Type == EFPenalty.PenaltyType.Flag))
|
||||||
|
{
|
||||||
|
// remove their auto flag status after a week
|
||||||
|
CurrentServer.Logger.WriteInfo($"Unflagging {this} because the auto flag time has expired");
|
||||||
|
Unflag(Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTOFLAG_UNFLAG"], autoKickClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -49,24 +49,14 @@ namespace SharedLibraryCore.RCon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// timeout in seconds to wait for a socket send or receive before giving up
|
/// timeout in seconds to wait for a socket send or receive before giving up
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static TimeSpan SocketTimeout(int retryAttempt)
|
public static readonly int SocketTimeout = 10000;
|
||||||
{
|
|
||||||
return retryAttempt switch
|
|
||||||
{
|
|
||||||
1 => TimeSpan.FromMilliseconds(550),
|
|
||||||
2 => TimeSpan.FromMilliseconds(1000),
|
|
||||||
3 => TimeSpan.FromMilliseconds(2000),
|
|
||||||
4 => TimeSpan.FromMilliseconds(5000),
|
|
||||||
_ => TimeSpan.FromMilliseconds(10000),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// interval in milliseconds to wait before sending the next RCon request
|
/// interval in milliseconds to wait before sending the next RCon request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly int FloodProtectionInterval = 750;
|
public static readonly int FloodProtectionInterval = 650;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how many failed connection attempts before aborting connection
|
/// how many failed connection attempts before aborting connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly int AllowedConnectionFails = 5;
|
public static readonly int AllowedConnectionFails = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,12 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore
|
namespace SharedLibraryCore
|
||||||
{
|
{
|
||||||
@ -30,15 +28,14 @@ namespace SharedLibraryCore
|
|||||||
T7 = 8
|
T7 = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
public Server(ILogger<Server> logger, SharedLibraryCore.Interfaces.ILogger deprecatedLogger,
|
public Server(ServerConfiguration config, IManager mgr, IRConConnectionFactory rconConnectionFactory, IGameLogReaderFactory gameLogReaderFactory)
|
||||||
ServerConfiguration config, IManager mgr, IRConConnectionFactory rconConnectionFactory,
|
|
||||||
IGameLogReaderFactory gameLogReaderFactory)
|
|
||||||
{
|
{
|
||||||
Password = config.Password;
|
Password = config.Password;
|
||||||
IP = config.IPAddress;
|
IP = config.IPAddress;
|
||||||
Port = config.Port;
|
Port = config.Port;
|
||||||
Manager = mgr;
|
Manager = mgr;
|
||||||
Logger = deprecatedLogger;
|
Logger = Manager.GetLogger(this.EndPoint);
|
||||||
|
Logger.WriteInfo(this.ToString());
|
||||||
ServerConfig = config;
|
ServerConfig = config;
|
||||||
RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password);
|
RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password);
|
||||||
EventProcessing = new SemaphoreSlim(1, 1);
|
EventProcessing = new SemaphoreSlim(1, 1);
|
||||||
@ -50,7 +47,6 @@ namespace SharedLibraryCore
|
|||||||
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
|
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
|
||||||
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
|
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
|
||||||
this.gameLogReaderFactory = gameLogReaderFactory;
|
this.gameLogReaderFactory = gameLogReaderFactory;
|
||||||
ServerLogger = logger;
|
|
||||||
InitializeTokens();
|
InitializeTokens();
|
||||||
InitializeAutoMessages();
|
InitializeAutoMessages();
|
||||||
}
|
}
|
||||||
@ -126,8 +122,10 @@ namespace SharedLibraryCore
|
|||||||
/// <param name="message">Message to be sent to all players</param>
|
/// <param name="message">Message to be sent to all players</param>
|
||||||
public GameEvent Broadcast(string message, EFClient sender = null)
|
public GameEvent Broadcast(string message, EFClient sender = null)
|
||||||
{
|
{
|
||||||
string formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say ?? "", $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
|
string formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Say, $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
|
||||||
ServerLogger.LogDebug("All->" + message.StripColors());
|
#if DEBUG == true
|
||||||
|
Logger.WriteVerbose(message.StripColors());
|
||||||
|
#endif
|
||||||
|
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
@ -148,27 +146,18 @@ namespace SharedLibraryCore
|
|||||||
/// <param name="target">EFClient to send message to</param>
|
/// <param name="target">EFClient to send message to</param>
|
||||||
protected async Task Tell(string message, EFClient target)
|
protected async Task Tell(string message, EFClient target)
|
||||||
{
|
{
|
||||||
if (!Utilities.IsDevelopment)
|
#if !DEBUG
|
||||||
{
|
string formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Tell, target.ClientNumber, $"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
|
||||||
var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Tell,
|
if (target.ClientNumber > -1 && message.Length > 0 && target.Level != EFClient.Permission.Console)
|
||||||
target.ClientNumber,
|
await this.ExecuteCommandAsync(formattedMessage);
|
||||||
$"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
|
#else
|
||||||
if (target.ClientNumber > -1 && message.Length > 0 && target.Level != EFClient.Permission.Console)
|
Logger.WriteVerbose($"{target.ClientNumber}->{message.StripColors()}");
|
||||||
await this.ExecuteCommandAsync(formattedMessage);
|
await Task.CompletedTask;
|
||||||
}
|
#endif
|
||||||
else
|
|
||||||
{
|
|
||||||
ServerLogger.LogDebug("Tell[{clientNumber}]->{message}", target.ClientNumber, message.StripColors());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (target.Level == EFClient.Permission.Console)
|
if (target.Level == EFClient.Permission.Console)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
using (LogContext.PushProperty("Server", ToString()))
|
|
||||||
{
|
|
||||||
ServerLogger.LogInformation("Command output received: {message}", message);
|
|
||||||
}
|
|
||||||
Console.WriteLine(message.StripColors());
|
Console.WriteLine(message.StripColors());
|
||||||
Console.ForegroundColor = ConsoleColor.Gray;
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
}
|
}
|
||||||
@ -280,7 +269,7 @@ namespace SharedLibraryCore
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return (await this.GetDvarAsync("sv_customcallbacks", "0")).Value == "1";
|
return (await this.GetDvarAsync<string>("sv_customcallbacks")).Value == "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exceptions.DvarException)
|
catch (Exceptions.DvarException)
|
||||||
@ -291,8 +280,7 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
// Objects
|
// Objects
|
||||||
public IManager Manager { get; protected set; }
|
public IManager Manager { get; protected set; }
|
||||||
[Obsolete]
|
public ILogger Logger { get; private set; }
|
||||||
public SharedLibraryCore.Interfaces.ILogger Logger { get; private set; }
|
|
||||||
public ServerConfiguration ServerConfig { get; private set; }
|
public ServerConfiguration ServerConfig { get; private set; }
|
||||||
public List<Map> Maps { get; protected set; } = new List<Map>();
|
public List<Map> Maps { get; protected set; } = new List<Map>();
|
||||||
public List<Report> Reports { get; set; }
|
public List<Report> Reports { get; set; }
|
||||||
@ -331,7 +319,6 @@ namespace SharedLibraryCore
|
|||||||
public string IP { get; protected set; }
|
public string IP { get; protected set; }
|
||||||
public string Version { get; protected set; }
|
public string Version { get; protected set; }
|
||||||
public bool IsInitialized { get; set; }
|
public bool IsInitialized { get; set; }
|
||||||
protected readonly ILogger ServerLogger;
|
|
||||||
|
|
||||||
public int Port { get; private set; }
|
public int Port { get; private set; }
|
||||||
protected string FSGame;
|
protected string FSGame;
|
||||||
|
@ -5,20 +5,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Services
|
namespace SharedLibraryCore.Services
|
||||||
{
|
{
|
||||||
public class ChangeHistoryService : IEntityService<EFChangeHistory>
|
public class ChangeHistoryService : IEntityService<EFChangeHistory>
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public ChangeHistoryService(ILogger<ChangeHistoryService> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<EFChangeHistory> Create(EFChangeHistory entity)
|
public Task<EFChangeHistory> Create(EFChangeHistory entity)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -88,7 +79,8 @@ namespace SharedLibraryCore.Services
|
|||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Could not persist change @{change}", change);
|
e.Owner.Logger.WriteWarning(ex.Message);
|
||||||
|
e.Owner.Logger.WriteDebug(ex.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
|
@ -8,28 +8,22 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Serilog.Context;
|
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Services
|
namespace SharedLibraryCore.Services
|
||||||
{
|
{
|
||||||
public class ClientService : IEntityService<EFClient>, IResourceQueryHelper<FindClientRequest, FindClientResult>
|
public class ClientService : IEntityService<EFClient>, IResourceQueryHelper<FindClientRequest, FindClientResult>
|
||||||
{
|
{
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public ClientService(ILogger<ClientService> logger, IDatabaseContextFactory databaseContextFactory)
|
public ClientService(IDatabaseContextFactory databaseContextFactory)
|
||||||
{
|
{
|
||||||
_contextFactory = databaseContextFactory;
|
_contextFactory = databaseContextFactory;
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<EFClient> Create(EFClient entity)
|
public async Task<EFClient> Create(EFClient entity)
|
||||||
{
|
{
|
||||||
using (var context = new DatabaseContext())
|
using (var context = new DatabaseContext())
|
||||||
using (LogContext.PushProperty("Server", entity?.CurrentServer?.ToString()))
|
|
||||||
{
|
{
|
||||||
int? linkId = null;
|
int? linkId = null;
|
||||||
int? aliasId = null;
|
int? aliasId = null;
|
||||||
@ -46,13 +40,13 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
linkId = existingAliases.OrderBy(_alias => _alias.LinkId).First().LinkId;
|
linkId = existingAliases.OrderBy(_alias => _alias.LinkId).First().LinkId;
|
||||||
|
|
||||||
_logger.LogDebug("[create] client with new GUID {entity} has existing link {linkId}", entity.ToString(), linkId);
|
entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing link {linkId}");
|
||||||
|
|
||||||
var existingExactAlias = existingAliases.FirstOrDefault(_alias => _alias.Name == entity.Name);
|
var existingExactAlias = existingAliases.FirstOrDefault(_alias => _alias.Name == entity.Name);
|
||||||
|
|
||||||
if (existingExactAlias != null)
|
if (existingExactAlias != null)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("[create] client with new GUID {entity} has existing alias {aliasId}", entity.ToString(), existingExactAlias.AliasId);
|
entity.CurrentServer.Logger.WriteDebug($"[create] client with new GUID {entity} has existing alias {existingExactAlias.AliasId}");
|
||||||
aliasId = existingExactAlias.AliasId;
|
aliasId = existingExactAlias.AliasId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,13 +60,13 @@ namespace SharedLibraryCore.Services
|
|||||||
NetworkId = entity.NetworkId
|
NetworkId = entity.NetworkId
|
||||||
};
|
};
|
||||||
|
|
||||||
_logger.LogDebug("[create] adding {entity} to context", entity.ToString());
|
entity.CurrentServer.Logger.WriteDebug($"[create] adding {entity} to context");
|
||||||
context.Clients.Add(client);
|
context.Clients.Add(client);
|
||||||
|
|
||||||
// they're just using a new GUID
|
// they're just using a new GUID
|
||||||
if (aliasId.HasValue)
|
if (aliasId.HasValue)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("[create] setting {entity}'s alias id and linkid to ({aliasId}, {linkId})", entity.ToString(), aliasId, linkId);
|
entity.CurrentServer.Logger.WriteDebug($"[create] setting {entity}'s alias id and linkid to ({aliasId.Value}, {linkId.Value})");
|
||||||
client.CurrentAliasId = aliasId.Value;
|
client.CurrentAliasId = aliasId.Value;
|
||||||
client.AliasLinkId = linkId.Value;
|
client.AliasLinkId = linkId.Value;
|
||||||
}
|
}
|
||||||
@ -80,7 +74,7 @@ namespace SharedLibraryCore.Services
|
|||||||
// link was found but they don't have an exact alias
|
// link was found but they don't have an exact alias
|
||||||
else if (!aliasId.HasValue && linkId.HasValue)
|
else if (!aliasId.HasValue && linkId.HasValue)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("[create] setting {entity}'s linkid to {linkId}, but creating new alias", entity.ToString(), linkId);
|
entity.CurrentServer.Logger.WriteDebug($"[create] setting {entity}'s linkid to {linkId.Value}, but creating new alias");
|
||||||
client.AliasLinkId = linkId.Value;
|
client.AliasLinkId = linkId.Value;
|
||||||
client.CurrentAlias = new EFAlias()
|
client.CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
@ -95,7 +89,7 @@ namespace SharedLibraryCore.Services
|
|||||||
// brand new players (supposedly)
|
// brand new players (supposedly)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("[create] creating new Link and Alias for {entity}", entity.ToString());
|
entity.CurrentServer.Logger.WriteDebug($"[create] creating new Link and Alias for {entity}");
|
||||||
var link = new EFAliasLink();
|
var link = new EFAliasLink();
|
||||||
var alias = new EFAlias()
|
var alias = new EFAlias()
|
||||||
{
|
{
|
||||||
@ -120,139 +114,129 @@ namespace SharedLibraryCore.Services
|
|||||||
|
|
||||||
private async Task UpdateAlias(string originalName, int? ip, EFClient entity, DatabaseContext context)
|
private async Task UpdateAlias(string originalName, int? ip, EFClient entity, DatabaseContext context)
|
||||||
{
|
{
|
||||||
using (LogContext.PushProperty("Server", entity?.CurrentServer?.ToString()))
|
string name = originalName.CapClientName(EFAlias.MAX_NAME_LENGTH);
|
||||||
|
|
||||||
|
// entity is the tracked db context item
|
||||||
|
// get all aliases by IP address and LinkId
|
||||||
|
var iqAliases = context.Aliases
|
||||||
|
.Include(a => a.Link)
|
||||||
|
// we only want alias that have the same IP address or share a link
|
||||||
|
.Where(_alias => _alias.IPAddress == ip || (_alias.LinkId == entity.AliasLinkId));
|
||||||
|
|
||||||
|
var aliases = await iqAliases.ToListAsync();
|
||||||
|
var currentIPs = aliases.Where(_a2 => _a2.IPAddress != null).Select(_a2 => _a2.IPAddress).Distinct();
|
||||||
|
var floatingIPAliases = await context.Aliases.Where(_alias => currentIPs.Contains(_alias.IPAddress)).ToListAsync();
|
||||||
|
aliases.AddRange(floatingIPAliases);
|
||||||
|
|
||||||
|
// see if they have a matching IP + Name but new NetworkId
|
||||||
|
var existingExactAlias = aliases.OrderBy(_alias => _alias.LinkId).FirstOrDefault(a => a.Name == name && a.IPAddress == ip);
|
||||||
|
bool hasExactAliasMatch = existingExactAlias != null;
|
||||||
|
|
||||||
|
// if existing alias matches link them
|
||||||
|
var newAliasLink = existingExactAlias?.Link;
|
||||||
|
// if no exact matches find the first IP or LinkId that matches
|
||||||
|
newAliasLink = newAliasLink ?? aliases.OrderBy(_alias => _alias.LinkId).FirstOrDefault()?.Link;
|
||||||
|
// if no matches are found, use our current one ( it will become permanent )
|
||||||
|
newAliasLink = newAliasLink ?? entity.AliasLink;
|
||||||
|
|
||||||
|
bool hasExistingAlias = aliases.Count > 0;
|
||||||
|
bool isAliasLinkUpdated = newAliasLink.AliasLinkId != entity.AliasLink.AliasLinkId;
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
int distinctLinkCount = aliases.Select(_alias => _alias.LinkId).Distinct().Count();
|
||||||
|
// this happens when the link we found is different than the one we create before adding an IP
|
||||||
|
if (isAliasLinkUpdated || distinctLinkCount > 1)
|
||||||
{
|
{
|
||||||
string name = originalName.CapClientName(EFAlias.MAX_NAME_LENGTH);
|
entity.CurrentServer.Logger.WriteDebug($"[updatealias] found a link for {entity} so we are updating link from {entity.AliasLink.AliasLinkId} to {newAliasLink.AliasLinkId}");
|
||||||
|
|
||||||
// entity is the tracked db context item
|
var completeAliasLinkIds = aliases.Select(_item => _item.LinkId)
|
||||||
// get all aliases by IP address and LinkId
|
.Append(entity.AliasLinkId)
|
||||||
var iqAliases = context.Aliases
|
.Distinct()
|
||||||
.Include(a => a.Link)
|
.ToList();
|
||||||
// we only want alias that have the same IP address or share a link
|
|
||||||
.Where(_alias => _alias.IPAddress == ip || (_alias.LinkId == entity.AliasLinkId));
|
|
||||||
|
|
||||||
var aliases = await iqAliases.ToListAsync();
|
entity.CurrentServer.Logger.WriteDebug($"[updatealias] updating aliasLinks {string.Join(',', completeAliasLinkIds)} for IP {ip} to {newAliasLink.AliasLinkId}");
|
||||||
var currentIPs = aliases.Where(_a2 => _a2.IPAddress != null).Select(_a2 => _a2.IPAddress).Distinct();
|
|
||||||
var floatingIPAliases = await context.Aliases.Where(_alias => currentIPs.Contains(_alias.IPAddress))
|
|
||||||
.ToListAsync();
|
|
||||||
aliases.AddRange(floatingIPAliases);
|
|
||||||
|
|
||||||
// see if they have a matching IP + Name but new NetworkId
|
// update all the clients that have the old alias link
|
||||||
var existingExactAlias = aliases.OrderBy(_alias => _alias.LinkId)
|
await context.Clients
|
||||||
.FirstOrDefault(a => a.Name == name && a.IPAddress == ip);
|
.Where(_client => completeAliasLinkIds.Contains(_client.AliasLinkId))
|
||||||
bool hasExactAliasMatch = existingExactAlias != null;
|
.ForEachAsync(_client => _client.AliasLinkId = newAliasLink.AliasLinkId);
|
||||||
|
|
||||||
// if existing alias matches link them
|
// we also need to update all the penalties or they get deleted
|
||||||
var newAliasLink = existingExactAlias?.Link;
|
// scenario
|
||||||
// if no exact matches find the first IP or LinkId that matches
|
// link1 joins with ip1
|
||||||
newAliasLink = newAliasLink ?? aliases.OrderBy(_alias => _alias.LinkId).FirstOrDefault()?.Link;
|
// link2 joins with ip2,
|
||||||
// if no matches are found, use our current one ( it will become permanent )
|
// link2 receives penalty
|
||||||
newAliasLink = newAliasLink ?? entity.AliasLink;
|
// link2 joins with ip1
|
||||||
|
// pre existing link for link2 detected
|
||||||
|
// link2 is deleted
|
||||||
|
// link2 penalties are orphaned
|
||||||
|
await context.Penalties
|
||||||
|
.Where(_penalty => completeAliasLinkIds.Contains(_penalty.LinkId))
|
||||||
|
.ForEachAsync(_penalty => _penalty.LinkId = newAliasLink.AliasLinkId);
|
||||||
|
|
||||||
bool hasExistingAlias = aliases.Count > 0;
|
entity.AliasLink = newAliasLink;
|
||||||
bool isAliasLinkUpdated = newAliasLink.AliasLinkId != entity.AliasLink.AliasLinkId;
|
entity.AliasLinkId = newAliasLink.AliasLinkId;
|
||||||
|
|
||||||
|
// update all previous aliases
|
||||||
|
await context.Aliases
|
||||||
|
.Where(_alias => completeAliasLinkIds.Contains(_alias.LinkId))
|
||||||
|
.ForEachAsync(_alias => _alias.LinkId = newAliasLink.AliasLinkId);
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
int distinctLinkCount = aliases.Select(_alias => _alias.LinkId).Distinct().Count();
|
// we want to delete the now inactive alias
|
||||||
// this happens when the link we found is different than the one we create before adding an IP
|
if (newAliasLink.AliasLinkId != entity.AliasLinkId)
|
||||||
if (isAliasLinkUpdated || distinctLinkCount > 1)
|
|
||||||
{
|
{
|
||||||
_logger.LogDebug(
|
context.AliasLinks.Remove(entity.AliasLink);
|
||||||
"[updatealias] found a link for {entity} so we are updating link from {oldAliasLinkId} to {newAliasLinkId}",
|
await context.SaveChangesAsync();
|
||||||
entity.ToString(), entity.AliasLink.AliasLinkId, newAliasLink.AliasLinkId);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var completeAliasLinkIds = aliases.Select(_item => _item.LinkId)
|
// the existing alias matches ip and name, so we can just ignore the temporary one
|
||||||
.Append(entity.AliasLinkId)
|
if (hasExactAliasMatch)
|
||||||
.Distinct()
|
{
|
||||||
.ToList();
|
entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} has exact alias match");
|
||||||
|
|
||||||
_logger.LogDebug("[updatealias] updating aliasLinks {links} for IP {ip} to {linkId}",
|
var oldAlias = entity.CurrentAlias;
|
||||||
string.Join(',', completeAliasLinkIds), ip, newAliasLink.AliasLinkId);
|
entity.CurrentAliasId = existingExactAlias.AliasId;
|
||||||
|
entity.CurrentAlias = existingExactAlias;
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
// update all the clients that have the old alias link
|
// the alias is the same so we can just remove it
|
||||||
|
if (oldAlias.AliasId != existingExactAlias.AliasId && oldAlias.AliasId > 0)
|
||||||
|
{
|
||||||
await context.Clients
|
await context.Clients
|
||||||
.Where(_client => completeAliasLinkIds.Contains(_client.AliasLinkId))
|
.Where(_client => _client.CurrentAliasId == oldAlias.AliasId)
|
||||||
.ForEachAsync(_client => _client.AliasLinkId = newAliasLink.AliasLinkId);
|
.ForEachAsync(_client => _client.CurrentAliasId = existingExactAlias.AliasId);
|
||||||
|
|
||||||
// we also need to update all the penalties or they get deleted
|
|
||||||
// scenario
|
|
||||||
// link1 joins with ip1
|
|
||||||
// link2 joins with ip2,
|
|
||||||
// link2 receives penalty
|
|
||||||
// link2 joins with ip1
|
|
||||||
// pre existing link for link2 detected
|
|
||||||
// link2 is deleted
|
|
||||||
// link2 penalties are orphaned
|
|
||||||
await context.Penalties
|
|
||||||
.Where(_penalty => completeAliasLinkIds.Contains(_penalty.LinkId))
|
|
||||||
.ForEachAsync(_penalty => _penalty.LinkId = newAliasLink.AliasLinkId);
|
|
||||||
|
|
||||||
entity.AliasLink = newAliasLink;
|
|
||||||
entity.AliasLinkId = newAliasLink.AliasLinkId;
|
|
||||||
|
|
||||||
// update all previous aliases
|
|
||||||
await context.Aliases
|
|
||||||
.Where(_alias => completeAliasLinkIds.Contains(_alias.LinkId))
|
|
||||||
.ForEachAsync(_alias => _alias.LinkId = newAliasLink.AliasLinkId);
|
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
// we want to delete the now inactive alias
|
|
||||||
if (newAliasLink.AliasLinkId != entity.AliasLinkId)
|
if (context.Entry(oldAlias).State != EntityState.Deleted)
|
||||||
{
|
{
|
||||||
context.AliasLinks.Remove(entity.AliasLink);
|
entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} has exact alias match, so we're going to try to remove aliasId {oldAlias.AliasId} with linkId {oldAlias.AliasId}");
|
||||||
|
context.Aliases.Remove(oldAlias);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the existing alias matches ip and name, so we can just ignore the temporary one
|
// theres no exact match, but they've played before with the GUID or IP
|
||||||
if (hasExactAliasMatch)
|
else
|
||||||
|
{
|
||||||
|
entity.CurrentServer.Logger.WriteDebug($"[updatealias] {entity} is using a new alias");
|
||||||
|
|
||||||
|
var newAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
_logger.LogDebug("[updatealias] {entity} has exact alias match", entity.ToString());
|
DateAdded = DateTime.UtcNow,
|
||||||
|
IPAddress = ip,
|
||||||
|
LinkId = newAliasLink.AliasLinkId,
|
||||||
|
Name = name,
|
||||||
|
SearchableName = name.StripColors().ToLower(),
|
||||||
|
Active = true,
|
||||||
|
};
|
||||||
|
|
||||||
var oldAlias = entity.CurrentAlias;
|
entity.CurrentAlias = newAlias;
|
||||||
entity.CurrentAliasId = existingExactAlias.AliasId;
|
entity.CurrentAliasId = 0;
|
||||||
entity.CurrentAlias = existingExactAlias;
|
await context.SaveChangesAsync();
|
||||||
await context.SaveChangesAsync();
|
|
||||||
|
|
||||||
// the alias is the same so we can just remove it
|
|
||||||
if (oldAlias.AliasId != existingExactAlias.AliasId && oldAlias.AliasId > 0)
|
|
||||||
{
|
|
||||||
await context.Clients
|
|
||||||
.Where(_client => _client.CurrentAliasId == oldAlias.AliasId)
|
|
||||||
.ForEachAsync(_client => _client.CurrentAliasId = existingExactAlias.AliasId);
|
|
||||||
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
|
|
||||||
if (context.Entry(oldAlias).State != EntityState.Deleted)
|
|
||||||
{
|
|
||||||
_logger.LogDebug(
|
|
||||||
"[updatealias] {entity} has exact alias match, so we're going to try to remove aliasId {aliasId} with linkId {linkId}",
|
|
||||||
entity.ToString(), oldAlias.AliasId, oldAlias.LinkId);
|
|
||||||
context.Aliases.Remove(oldAlias);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// theres no exact match, but they've played before with the GUID or IP
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogDebug("[updatealias] {entity} is using a new alias", entity.ToString());
|
|
||||||
|
|
||||||
var newAlias = new EFAlias()
|
|
||||||
{
|
|
||||||
DateAdded = DateTime.UtcNow,
|
|
||||||
IPAddress = ip,
|
|
||||||
LinkId = newAliasLink.AliasLinkId,
|
|
||||||
Name = name,
|
|
||||||
SearchableName = name.StripColors().ToLower(),
|
|
||||||
Active = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
entity.CurrentAlias = newAlias;
|
|
||||||
entity.CurrentAliasId = 0;
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,29 +261,29 @@ namespace SharedLibraryCore.Services
|
|||||||
entity.Level = newPermission;
|
entity.Level = newPermission;
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
|
|
||||||
using (LogContext.PushProperty("Server", entity?.CurrentServer?.ToString()))
|
#if DEBUG == true
|
||||||
|
temporalClient.CurrentServer.Logger.WriteDebug($"Updated {temporalClient.ClientId} to {newPermission}");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var linkedPermissionSet = new[] { Permission.Banned, Permission.Flagged };
|
||||||
|
// if their permission level has been changed to level that needs to be updated on all accounts
|
||||||
|
if (linkedPermissionSet.Contains(newPermission) || linkedPermissionSet.Contains(oldPermission))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Updated {clientId} to {newPermission}", temporalClient.ClientId, newPermission);
|
//get all clients that have the same linkId
|
||||||
|
var iqMatchingClients = ctx.Clients
|
||||||
|
.Where(_client => _client.AliasLinkId == entity.AliasLinkId);
|
||||||
|
|
||||||
var linkedPermissionSet = new[] {Permission.Banned, Permission.Flagged};
|
// this updates the level for all the clients with the same LinkId
|
||||||
// if their permission level has been changed to level that needs to be updated on all accounts
|
// only if their new level is flagged or banned
|
||||||
if (linkedPermissionSet.Contains(newPermission) || linkedPermissionSet.Contains(oldPermission))
|
await iqMatchingClients.ForEachAsync(_client =>
|
||||||
{
|
{
|
||||||
//get all clients that have the same linkId
|
_client.Level = newPermission;
|
||||||
var iqMatchingClients = ctx.Clients
|
#if DEBUG == true
|
||||||
.Where(_client => _client.AliasLinkId == entity.AliasLinkId);
|
temporalClient.CurrentServer.Logger.WriteDebug($"Updated linked {_client.ClientId} to {newPermission}");
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
|
||||||
// this updates the level for all the clients with the same LinkId
|
await ctx.SaveChangesAsync();
|
||||||
// only if their new level is flagged or banned
|
|
||||||
await iqMatchingClients.ForEachAsync(_client =>
|
|
||||||
{
|
|
||||||
_client.Level = newPermission;
|
|
||||||
_logger.LogInformation("Updated linked {clientId} to {newPermission}", _client.ClientId,
|
|
||||||
newPermission);
|
|
||||||
});
|
|
||||||
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,7 +432,7 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
if (temporalClient.ClientId < 1)
|
if (temporalClient.ClientId < 1)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("[update] {client} needs to be updated but they do not have a valid client id, ignoring..", temporalClient.ToString());
|
temporalClient.CurrentServer?.Logger.WriteDebug($"[update] {temporalClient} needs to be updated but they do not have a valid client id, ignoring..");
|
||||||
// note: we never do anything with the result of this so we can safely return null
|
// note: we never do anything with the result of this so we can safely return null
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<ApplicationIcon />
|
||||||
|
<StartupObject />
|
||||||
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
||||||
<Version>2.4.10</Version>
|
<Version>2.4.10</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
@ -19,9 +21,8 @@
|
|||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<Description>Shared Library for IW4MAdmin</Description>
|
<Description>Shared Library for IW4MAdmin</Description>
|
||||||
<AssemblyVersion>2020.11.11.1</AssemblyVersion>
|
<AssemblyVersion>2.4.10.0</AssemblyVersion>
|
||||||
<FileVersion>2020.11.11.1</FileVersion>
|
<FileVersion>2.4.10.0</FileVersion>
|
||||||
<PackageVersion>2020.11.11.1</PackageVersion>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
||||||
@ -53,7 +54,6 @@
|
|||||||
<PackageReference Include="Npgsql" Version="4.1.4" />
|
<PackageReference Include="Npgsql" Version="4.1.4" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.2" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.2" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
|
||||||
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -17,18 +17,14 @@ using System.Text;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
using static SharedLibraryCore.Database.Models.EFPenalty;
|
using static SharedLibraryCore.Database.Models.EFPenalty;
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore
|
namespace SharedLibraryCore
|
||||||
{
|
{
|
||||||
public static class Utilities
|
public static class Utilities
|
||||||
{
|
{
|
||||||
// note: this is only to be used by classes not created by dependency injection
|
|
||||||
public static ILogger DefaultLogger { get; set; }
|
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}{Path.DirectorySeparatorChar}";
|
public static string OperatingDirectory => $"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}{Path.DirectorySeparatorChar}";
|
||||||
#else
|
#else
|
||||||
@ -885,7 +881,8 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.LogError(e, $"Could not create penalty of type {penalty.Type.ToString()}");
|
logger.WriteWarning($"Could not create penalty of type {penalty.Type.ToString()}");
|
||||||
|
logger.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FakeItEasy" Version="6.2.0" />
|
<PackageReference Include="FakeItEasy" Version="6.2.0" />
|
||||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">
|
||||||
|
@ -10,7 +10,6 @@ using SharedLibraryCore.Configuration;
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using static SharedLibraryCore.GameEvent;
|
using static SharedLibraryCore.GameEvent;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
@ -19,6 +18,7 @@ namespace ApplicationTests
|
|||||||
{
|
{
|
||||||
private EventLogTest eventLogData;
|
private EventLogTest eventLogData;
|
||||||
private IServiceProvider serviceProvider;
|
private IServiceProvider serviceProvider;
|
||||||
|
private ILogger fakeLogger;
|
||||||
private ApplicationConfiguration appConfig;
|
private ApplicationConfiguration appConfig;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
@ -27,12 +27,13 @@ namespace ApplicationTests
|
|||||||
eventLogData = JsonConvert.DeserializeObject<EventLogTest>(System.IO.File.ReadAllText("Files/GameEvents.json"));
|
eventLogData = JsonConvert.DeserializeObject<EventLogTest>(System.IO.File.ReadAllText("Files/GameEvents.json"));
|
||||||
appConfig = ConfigurationGenerators.CreateApplicationConfiguration();
|
appConfig = ConfigurationGenerators.CreateApplicationConfiguration();
|
||||||
|
|
||||||
|
fakeLogger = A.Fake<ILogger>();
|
||||||
serviceProvider = new ServiceCollection()
|
serviceProvider = new ServiceCollection()
|
||||||
.AddSingleton(A.Fake<ILogger>())
|
|
||||||
.AddSingleton<BaseEventParser>()
|
.AddSingleton<BaseEventParser>()
|
||||||
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
||||||
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
||||||
.AddSingleton(appConfig)
|
.AddSingleton(appConfig)
|
||||||
|
.AddSingleton(fakeLogger)
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +86,18 @@ namespace ApplicationTests
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCustomEventParsingLogsWarningOnException()
|
||||||
|
{
|
||||||
|
var eventParser = serviceProvider.GetService<BaseEventParser>();
|
||||||
|
|
||||||
|
eventParser.RegisterCustomEvent("test", "test", (a, b, c) => throw new Exception());
|
||||||
|
eventParser.GenerateGameEvent("12:12 test");
|
||||||
|
|
||||||
|
A.CallTo(() => fakeLogger.WriteWarning(A<string>.Ignored))
|
||||||
|
.MustHaveHappenedOnceExactly();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Test_CustomCommandPrefix_Parses()
|
public void Test_CustomCommandPrefix_Parses()
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using FakeItEasy;
|
using FakeItEasy;
|
||||||
using IW4MAdmin.Application.RconParsers;
|
using IW4MAdmin.Application.RconParsers;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
@ -9,12 +8,10 @@ namespace ApplicationTests
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BaseRConParserTests
|
public class BaseRConParserTests
|
||||||
{
|
{
|
||||||
private readonly ILogger<BaseRConParser> _fakeLogger = A.Fake<ILogger<BaseRConParser>>();
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void SetDvarAsync_FormatStringType()
|
public void SetDvarAsync_FormatStringType()
|
||||||
{
|
{
|
||||||
var parser = new BaseRConParser(_fakeLogger, A.Fake<IParserRegexFactory>());
|
var parser = new BaseRConParser(A.Fake<IParserRegexFactory>());
|
||||||
var connection = A.Fake<IRConConnection>();
|
var connection = A.Fake<IRConConnection>();
|
||||||
|
|
||||||
parser.SetDvarAsync(connection, "test", "test").Wait();
|
parser.SetDvarAsync(connection, "test", "test").Wait();
|
||||||
@ -26,7 +23,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void SetDvarAsync_FormatEmptyStringTypeIncludesQuotes()
|
public void SetDvarAsync_FormatEmptyStringTypeIncludesQuotes()
|
||||||
{
|
{
|
||||||
var parser = new BaseRConParser(_fakeLogger, A.Fake<IParserRegexFactory>());
|
var parser = new BaseRConParser(A.Fake<IParserRegexFactory>());
|
||||||
var connection = A.Fake<IRConConnection>();
|
var connection = A.Fake<IRConConnection>();
|
||||||
|
|
||||||
parser.SetDvarAsync(connection, "test", "").Wait();
|
parser.SetDvarAsync(connection, "test", "").Wait();
|
||||||
@ -38,7 +35,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void SetDvarAsync_FormatsNonString()
|
public void SetDvarAsync_FormatsNonString()
|
||||||
{
|
{
|
||||||
var parser = new BaseRConParser(_fakeLogger, A.Fake<IParserRegexFactory>());
|
var parser = new BaseRConParser(A.Fake<IParserRegexFactory>());
|
||||||
var connection = A.Fake<IRConConnection>();
|
var connection = A.Fake<IRConConnection>();
|
||||||
|
|
||||||
parser.SetDvarAsync(connection, "test", 123).Wait();
|
parser.SetDvarAsync(connection, "test", 123).Wait();
|
||||||
|
@ -8,7 +8,6 @@ using SharedLibraryCore.Database.Models;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using SharedLibraryCore.Configuration;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
|
@ -14,15 +14,13 @@ using SharedLibraryCore;
|
|||||||
using ApplicationTests.Mocks;
|
using ApplicationTests.Mocks;
|
||||||
using SharedLibraryCore.Services;
|
using SharedLibraryCore.Services;
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
using FluentAssertions;
|
|
||||||
using FluentAssertions.Extensions;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CommandTests
|
public class CommandTests
|
||||||
{
|
{
|
||||||
|
ILogger logger;
|
||||||
private IServiceProvider serviceProvider;
|
private IServiceProvider serviceProvider;
|
||||||
private ITranslationLookup transLookup;
|
private ITranslationLookup transLookup;
|
||||||
private CommandConfiguration cmdConfig;
|
private CommandConfiguration cmdConfig;
|
||||||
@ -34,13 +32,12 @@ namespace ApplicationTests
|
|||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
|
logger = A.Fake<ILogger>();
|
||||||
|
cmdConfig = new CommandConfiguration();
|
||||||
|
|
||||||
serviceProvider = new ServiceCollection()
|
serviceProvider = new ServiceCollection()
|
||||||
.BuildBase(new EventHandlerMock(true))
|
.BuildBase(new EventHandlerMock(true))
|
||||||
.AddSingleton(A.Fake<ClientService>())
|
.AddSingleton(A.Fake<ClientService>())
|
||||||
.AddSingleton<LoadMapCommand>()
|
|
||||||
.AddSingleton<SetLevelCommand>()
|
|
||||||
.AddSingleton<RunAsCommand>()
|
|
||||||
.AddSingleton<PrivateMessageAdminsCommand>()
|
|
||||||
.BuildServiceProvider()
|
.BuildServiceProvider()
|
||||||
.SetupTestHooks();
|
.SetupTestHooks();
|
||||||
|
|
||||||
@ -49,12 +46,6 @@ namespace ApplicationTests
|
|||||||
transLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
transLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
||||||
clientService = serviceProvider.GetRequiredService<ClientService>();
|
clientService = serviceProvider.GetRequiredService<ClientService>();
|
||||||
appConfig = serviceProvider.GetRequiredService<ApplicationConfiguration>();
|
appConfig = serviceProvider.GetRequiredService<ApplicationConfiguration>();
|
||||||
appConfig.MapChangeDelaySeconds = 1;
|
|
||||||
cmdConfig = serviceProvider.GetRequiredService<CommandConfiguration>();
|
|
||||||
serviceProvider.GetService<IW4MServer>().RconParser =
|
|
||||||
serviceProvider.GetService<IRConParser>();
|
|
||||||
|
|
||||||
Utilities.DefaultLogger = serviceProvider.GetRequiredService<ILogger>();
|
|
||||||
|
|
||||||
A.CallTo(() => manager.GetClientService())
|
A.CallTo(() => manager.GetClientService())
|
||||||
.Returns(clientService);
|
.Returns(clientService);
|
||||||
@ -78,7 +69,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_RunAsFailsOnSelf()
|
public async Task Test_RunAsFailsOnSelf()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
|
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
|
|
||||||
@ -97,7 +88,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_RunAsFailsOnHigherPrivilege()
|
public async Task Test_RunAsFailsOnHigherPrivilege()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
|
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
target.Level = EFClient.Permission.Administrator;
|
target.Level = EFClient.Permission.Administrator;
|
||||||
@ -120,7 +111,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_RunAsFailsOnSamePrivilege()
|
public async Task Test_RunAsFailsOnSamePrivilege()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
|
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
target.Level = EFClient.Permission.Administrator;
|
target.Level = EFClient.Permission.Administrator;
|
||||||
@ -143,7 +134,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_RunAsFailsOnDisallowedCommand()
|
public async Task Test_RunAsFailsOnDisallowedCommand()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
|
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
target.Level = EFClient.Permission.Moderator;
|
target.Level = EFClient.Permission.Moderator;
|
||||||
@ -169,7 +160,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_RunAsQueuesEventAndResponse()
|
public async Task Test_RunAsQueuesEventAndResponse()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<RunAsCommand>();
|
var cmd = new RunAsCommand(cmdConfig, transLookup);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
target.Level = EFClient.Permission.Moderator;
|
target.Level = EFClient.Permission.Moderator;
|
||||||
@ -196,7 +187,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_SetLevelFailOnSelf()
|
public async Task Test_SetLevelFailOnSelf()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
target.Level = Permission.Owner;
|
target.Level = Permission.Owner;
|
||||||
@ -220,7 +211,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelFailWithSourcePrivilegeTooLow()
|
public async Task Test_SetLevelFailWithSourcePrivilegeTooLow()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Moderator;
|
origin.Level = Permission.Moderator;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -248,7 +239,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelFailWithExistingOwner_AndOnlyOneOwnerAllowed()
|
public async Task Test_SetLevelFailWithExistingOwner_AndOnlyOneOwnerAllowed()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
target.Level = Permission.User;
|
target.Level = Permission.User;
|
||||||
@ -275,7 +266,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelFailWithStepPrivilegesDisabled_AndNonOwner()
|
public async Task Test_SetLevelFailWithStepPrivilegesDisabled_AndNonOwner()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.SeniorAdmin;
|
origin.Level = Permission.SeniorAdmin;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -303,7 +294,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelFailWithStepPrivilegesEnabled_ButNewPermissionTooHigh()
|
public async Task Test_SetLevelFailWithStepPrivilegesEnabled_ButNewPermissionTooHigh()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Moderator;
|
origin.Level = Permission.Moderator;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -329,7 +320,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelFailInvalidGroup()
|
public async Task Test_SetLevelFailInvalidGroup()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Owner;
|
origin.Level = Permission.Owner;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -354,7 +345,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelSucceedWithNoExistingOwner_AndOnlyOneOwnerAllowed()
|
public async Task Test_SetLevelSucceedWithNoExistingOwner_AndOnlyOneOwnerAllowed()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Owner;
|
origin.Level = Permission.Owner;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -382,7 +373,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelOwnerSucceedWithMultiOwnerAllowed()
|
public async Task Test_SetLevelOwnerSucceedWithMultiOwnerAllowed()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Owner;
|
origin.Level = Permission.Owner;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -411,7 +402,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelOwnerSucceedWithMultiOwnerAllowed_AndSteppedPrivileges()
|
public async Task Test_SetLevelOwnerSucceedWithMultiOwnerAllowed_AndSteppedPrivileges()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Owner;
|
origin.Level = Permission.Owner;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -441,7 +432,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelSucceedWithSteppedPrivileges()
|
public async Task Test_SetLevelSucceedWithSteppedPrivileges()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Moderator;
|
origin.Level = Permission.Moderator;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -470,7 +461,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelSucceed()
|
public async Task Test_SetLevelSucceed()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Owner;
|
origin.Level = Permission.Owner;
|
||||||
var target = ClientGenerators.CreateBasicClient(server);
|
var target = ClientGenerators.CreateBasicClient(server);
|
||||||
@ -499,7 +490,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_SetLevelSucceed_AndFindsIngameClient()
|
public async Task Test_SetLevelSucceed_AndFindsIngameClient()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
|
var cmd = new SetLevelCommand(cmdConfig, transLookup, logger);
|
||||||
var origin = ClientGenerators.CreateBasicClient(server);
|
var origin = ClientGenerators.CreateBasicClient(server);
|
||||||
origin.Level = Permission.Owner;
|
origin.Level = Permission.Owner;
|
||||||
var databaseTarget = ClientGenerators.CreateDatabaseClient();
|
var databaseTarget = ClientGenerators.CreateDatabaseClient();
|
||||||
@ -551,14 +542,14 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_PrivateMessageAdmins_HappyPath()
|
public async Task Test_PrivateMessageAdmins_HappyPath()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<PrivateMessageAdminsCommand>();
|
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var origin = ClientGenerators.CreateDatabaseClient();
|
var origin = ClientGenerators.CreateDatabaseClient();
|
||||||
origin.Level = Permission.Administrator;
|
origin.Level = Permission.Administrator;
|
||||||
origin.CurrentServer = server;
|
origin.CurrentServer = server;
|
||||||
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, "", server);
|
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, "", server);
|
||||||
cmdConfig.Commands.Add(nameof(PrivateMessageAdminsCommand), new CommandProperties { SupportedGames = new[] { server.GameName } });
|
cmdConfig.Commands.Add(nameof(PrivateMessageAdminsCommand), new CommandProperties { SupportedGames = new[] { server.GameName } });
|
||||||
|
|
||||||
server.Clients[0] = origin;
|
server.Clients[0] = origin;
|
||||||
server.Clients[1] = origin;
|
server.Clients[1] = origin;
|
||||||
await cmd.ExecuteAsync(gameEvent);
|
await cmd.ExecuteAsync(gameEvent);
|
||||||
@ -570,7 +561,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_PrivateMessageAdmins_GameNotSupported()
|
public async Task Test_PrivateMessageAdmins_GameNotSupported()
|
||||||
{
|
{
|
||||||
var cmd = serviceProvider.GetRequiredService<PrivateMessageAdminsCommand>();
|
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var origin = ClientGenerators.CreateDatabaseClient();
|
var origin = ClientGenerators.CreateDatabaseClient();
|
||||||
origin.Level = Permission.Administrator;
|
origin.Level = Permission.Administrator;
|
||||||
@ -587,46 +578,5 @@ namespace ApplicationTests
|
|||||||
Assert.AreEqual(expectedEvents, mockEventHandler.Events.Count(_event => _event.Type == GameEvent.EventType.Tell));
|
Assert.AreEqual(expectedEvents, mockEventHandler.Events.Count(_event => _event.Type == GameEvent.EventType.Tell));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region LOADMAP
|
|
||||||
[Test]
|
|
||||||
public void Test_LoadMap_WaitsAppropriateTime_BeforeExecutingCommand()
|
|
||||||
{
|
|
||||||
var cmd = serviceProvider.GetRequiredService<LoadMapCommand>();
|
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
||||||
var rconParser = serviceProvider.GetRequiredService<IRConParser>();
|
|
||||||
server.Maps.Add(new Map()
|
|
||||||
{
|
|
||||||
Name = "mp_test",
|
|
||||||
Alias = "test"
|
|
||||||
});
|
|
||||||
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, server.Maps.First().Name, server);
|
|
||||||
|
|
||||||
Func<Task> act = () => cmd.ExecuteAsync(gameEvent);
|
|
||||||
|
|
||||||
act.ExecutionTime().Should().BeCloseTo(appConfig.MapChangeDelaySeconds.Seconds(), 500.Milliseconds());
|
|
||||||
A.CallTo(() => rconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, A<string>.Ignored))
|
|
||||||
.MustHaveHappened();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task Test_LoadMap_FindsMapName_FromPartialAlias()
|
|
||||||
{
|
|
||||||
var cmd = serviceProvider.GetRequiredService<LoadMapCommand>();
|
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
|
||||||
var rconParser = serviceProvider.GetRequiredService<IRConParser>();
|
|
||||||
server.Maps.Add(new Map()
|
|
||||||
{
|
|
||||||
Name = "mp_test",
|
|
||||||
Alias = "test"
|
|
||||||
});
|
|
||||||
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, server.Maps.First().Name, server);
|
|
||||||
|
|
||||||
await cmd.ExecuteAsync(gameEvent);
|
|
||||||
|
|
||||||
A.CallTo(() => rconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, A<string>.That.Contains(server.Maps[0].Name)))
|
|
||||||
.MustHaveHappened();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,10 @@ using FakeItEasy;
|
|||||||
using IW4MAdmin;
|
using IW4MAdmin;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using SharedLibraryCore.Services;
|
||||||
using System;
|
using System;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
@ -27,22 +28,17 @@ namespace ApplicationTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
var manager = A.Fake<IManager>();
|
var manager = A.Fake<IManager>();
|
||||||
|
var logger = A.Fake<ILogger>();
|
||||||
|
|
||||||
var transLookup = A.Fake<ITranslationLookup>();
|
A.CallTo(() => manager.GetLogger(A<long>.Ignored))
|
||||||
A.CallTo(() => transLookup[A<string>.Ignored])
|
.Returns(logger);
|
||||||
.Returns("test");
|
|
||||||
|
|
||||||
serviceCollection
|
serviceCollection.AddSingleton(logger)
|
||||||
.AddLogging()
|
|
||||||
.AddSingleton(A.Fake<ILogger>())
|
|
||||||
.AddSingleton(A.Fake<SharedLibraryCore.Interfaces.ILogger>())
|
|
||||||
.AddSingleton(new ServerConfiguration { IPAddress = "127.0.0.1", Port = 28960 })
|
|
||||||
.AddSingleton(manager)
|
.AddSingleton(manager)
|
||||||
.AddSingleton<IDatabaseContextFactory, DatabaseContextFactoryMock>()
|
.AddSingleton<IDatabaseContextFactory, DatabaseContextFactoryMock>()
|
||||||
.AddSingleton<IW4MServer>()
|
|
||||||
.AddSingleton(A.Fake<IRConConnectionFactory>())
|
.AddSingleton(A.Fake<IRConConnectionFactory>())
|
||||||
.AddSingleton(A.Fake<IRConConnection>())
|
.AddSingleton(A.Fake<IRConConnection>())
|
||||||
.AddSingleton(transLookup)
|
.AddSingleton(A.Fake<ITranslationLookup>())
|
||||||
.AddSingleton(A.Fake<IRConParser>())
|
.AddSingleton(A.Fake<IRConParser>())
|
||||||
.AddSingleton(A.Fake<IParserRegexFactory>())
|
.AddSingleton(A.Fake<IParserRegexFactory>())
|
||||||
.AddSingleton<DataFileLoader>()
|
.AddSingleton<DataFileLoader>()
|
||||||
@ -53,6 +49,12 @@ namespace ApplicationTests
|
|||||||
.AddSingleton(ConfigurationGenerators.CreateCommandConfiguration())
|
.AddSingleton(ConfigurationGenerators.CreateCommandConfiguration())
|
||||||
.AddSingleton<IConfigurationHandler<ApplicationConfiguration>, ApplicationConfigurationHandlerMock>();
|
.AddSingleton<IConfigurationHandler<ApplicationConfiguration>, ApplicationConfigurationHandlerMock>();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton(_sp => new IW4MServer(_sp.GetRequiredService<IManager>(), ConfigurationGenerators.CreateServerConfiguration(),
|
||||||
|
_sp.GetRequiredService<ITranslationLookup>(), _sp.GetRequiredService<IRConConnectionFactory>(), _sp.GetRequiredService<IGameLogReaderFactory>(), _sp.GetRequiredService<IMetaService>())
|
||||||
|
{
|
||||||
|
RconParser = _sp.GetRequiredService<IRConParser>()
|
||||||
|
});
|
||||||
|
|
||||||
return serviceCollection;
|
return serviceCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
using FakeItEasy;
|
using FakeItEasy;
|
||||||
|
using IW4MAdmin;
|
||||||
using IW4MAdmin.Application.IO;
|
using IW4MAdmin.Application.IO;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SharedLibraryCore;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
@ -18,24 +19,19 @@ namespace ApplicationTests
|
|||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
serviceProvider = new ServiceCollection()
|
serviceProvider = new ServiceCollection().BuildBase().BuildServiceProvider();
|
||||||
.BuildBase()
|
|
||||||
.AddSingleton(new Uri[] { new Uri("C:\\test.log")})
|
|
||||||
.AddSingleton(A.Fake<IGameLogReaderFactory>())
|
|
||||||
.AddSingleton<GameLogEventDetection>()
|
|
||||||
.BuildServiceProvider();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task GameLogEventDetection_WorksAfterFileSizeReset()
|
public async Task GameLogEventDetection_WorksAfterFileSizeReset()
|
||||||
{
|
{
|
||||||
var reader = A.Fake<IGameLogReader>();
|
var reader = A.Fake<IGameLogReader>();
|
||||||
var factory = serviceProvider.GetRequiredService<IGameLogReaderFactory>();
|
var factory = A.Fake<IGameLogReaderFactory>();
|
||||||
|
|
||||||
A.CallTo(() => factory.CreateGameLogReader(A<Uri[]>.Ignored, A<IEventParser>.Ignored))
|
A.CallTo(() => factory.CreateGameLogReader(A<Uri[]>.Ignored, A<IEventParser>.Ignored))
|
||||||
.Returns(reader);
|
.Returns(reader);
|
||||||
|
|
||||||
var detect = serviceProvider.GetRequiredService<GameLogEventDetection>();
|
var detect = new GameLogEventDetection(serviceProvider.GetService<IW4MServer>(), new Uri[] { new Uri("C:\\test.log") }, factory);
|
||||||
|
|
||||||
A.CallTo(() => reader.Length)
|
A.CallTo(() => reader.Length)
|
||||||
.Returns(100)
|
.Returns(100)
|
||||||
|
@ -11,11 +11,9 @@ using SharedLibraryCore.Database.Models;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ApplicationTests.Mocks;
|
using ApplicationTests.Mocks;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Exceptions;
|
using SharedLibraryCore.Exceptions;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
@ -41,8 +39,6 @@ namespace ApplicationTests
|
|||||||
fakeRConParser = serviceProvider.GetRequiredService<IRConParser>();
|
fakeRConParser = serviceProvider.GetRequiredService<IRConParser>();
|
||||||
mockEventHandler = serviceProvider.GetRequiredService<EventHandlerMock>();
|
mockEventHandler = serviceProvider.GetRequiredService<EventHandlerMock>();
|
||||||
appConfig = serviceProvider.GetRequiredService<ApplicationConfiguration>();
|
appConfig = serviceProvider.GetRequiredService<ApplicationConfiguration>();
|
||||||
serviceProvider.GetService<IW4MServer>().RconParser =
|
|
||||||
serviceProvider.GetService<IRConParser>();
|
|
||||||
|
|
||||||
var rconConnectionFactory = serviceProvider.GetRequiredService<IRConConnectionFactory>();
|
var rconConnectionFactory = serviceProvider.GetRequiredService<IRConConnectionFactory>();
|
||||||
|
|
||||||
@ -217,7 +213,7 @@ namespace ApplicationTests
|
|||||||
|
|
||||||
await server.Ban("test reason", target, origin);
|
await server.Ban("test reason", target, origin);
|
||||||
|
|
||||||
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
A.CallTo(() => fakeRConParser.ExecuteCommandAsync(fakeRConConnection, "kick"))
|
||||||
.MustHaveHappenedOnceExactly();
|
.MustHaveHappenedOnceExactly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +288,7 @@ namespace ApplicationTests
|
|||||||
|
|
||||||
await server.TempBan("test reason", TimeSpan.Zero, target, origin);
|
await server.TempBan("test reason", TimeSpan.Zero, target, origin);
|
||||||
|
|
||||||
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
A.CallTo(() => fakeRConParser.ExecuteCommandAsync(fakeRConConnection, "kick"))
|
||||||
.MustHaveHappenedOnceExactly();
|
.MustHaveHappenedOnceExactly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +310,7 @@ namespace ApplicationTests
|
|||||||
|
|
||||||
await server.TempBan("test reason", TimeSpan.Zero, target, origin);
|
await server.TempBan("test reason", TimeSpan.Zero, target, origin);
|
||||||
|
|
||||||
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
A.CallTo(() => fakeRConParser.ExecuteCommandAsync(fakeRConConnection, "kick"))
|
||||||
.MustHaveHappenedOnceExactly();
|
.MustHaveHappenedOnceExactly();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -350,7 +346,7 @@ namespace ApplicationTests
|
|||||||
|
|
||||||
await server.Kick("test reason", target, origin);
|
await server.Kick("test reason", target, origin);
|
||||||
|
|
||||||
A.CallTo(() => server.RconParser.ExecuteCommandAsync(A<IRConConnection>.Ignored, "kick"))
|
A.CallTo(() => fakeRConParser.ExecuteCommandAsync(fakeRConConnection, "kick"))
|
||||||
.MustHaveHappenedOnceExactly();
|
.MustHaveHappenedOnceExactly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,6 +529,9 @@ namespace ApplicationTests
|
|||||||
{
|
{
|
||||||
await server.ProcessUpdatesAsync(new System.Threading.CancellationToken());
|
await server.ProcessUpdatesAsync(new System.Threading.CancellationToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
A.CallTo(() => fakeLogger.WriteError(A<string>.Ignored))
|
||||||
|
.MustNotHaveHappened();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -556,6 +555,9 @@ namespace ApplicationTests
|
|||||||
await server.ExecuteEvent(e);
|
await server.ExecuteEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
A.CallTo(() => fakeLogger.WriteError(A<string>.Ignored))
|
||||||
|
.MustHaveHappenedOnceExactly();
|
||||||
|
|
||||||
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.ConnectionLost));
|
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.ConnectionLost));
|
||||||
Assert.AreEqual("err", (mockEventHandler.Events[0].Extra as NetworkException).Message);
|
Assert.AreEqual("err", (mockEventHandler.Events[0].Extra as NetworkException).Message);
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,11 @@ using SharedLibraryCore.Database.Models;
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.Services;
|
using SharedLibraryCore.Services;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
@ -51,7 +53,7 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task Test_GenericGuidClientIsKicked()
|
public async Task Test_GenericGuidClientIsKicked()
|
||||||
{
|
{
|
||||||
var plugin = new ScriptPlugin(serviceProvider.GetRequiredService<ILogger>(), Path.Join(PLUGIN_DIR, "SharedGUIDKick.js"), PLUGIN_DIR);
|
var plugin = new ScriptPlugin(Path.Join(PLUGIN_DIR, "SharedGUIDKick.js"), PLUGIN_DIR);
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
server.GameName = Server.Game.IW4;
|
server.GameName = Server.Game.IW4;
|
||||||
var client = ClientGenerators.CreateBasicClient(server, hasIp: false, clientState: EFClient.ClientState.Connecting);
|
var client = ClientGenerators.CreateBasicClient(server, hasIp: false, clientState: EFClient.ClientState.Connecting);
|
||||||
|
@ -1,32 +1,41 @@
|
|||||||
using FakeItEasy;
|
using FakeItEasy;
|
||||||
using IW4MAdmin;
|
using IW4MAdmin;
|
||||||
|
using IW4MAdmin.Application;
|
||||||
using IW4MAdmin.Application.EventParsers;
|
using IW4MAdmin.Application.EventParsers;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using System.Diagnostics;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ServerTests
|
public class ServerTests
|
||||||
{
|
{
|
||||||
private IServiceProvider _serviceProvider;
|
ILogger logger;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
_serviceProvider = new ServiceCollection()
|
logger = A.Fake<ILogger>();
|
||||||
.BuildBase()
|
|
||||||
.BuildServiceProvider();
|
void testLog(string msg) => Console.WriteLine(msg);
|
||||||
|
|
||||||
|
A.CallTo(() => logger.WriteError(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
|
A.CallTo(() => logger.WriteWarning(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
|
A.CallTo(() => logger.WriteInfo(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
|
A.CallTo(() => logger.WriteDebug(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void GameTimeFalseQuitTest()
|
public void GameTimeFalseQuitTest()
|
||||||
{
|
{
|
||||||
var server = _serviceProvider.GetRequiredService<IW4MServer>();
|
var mgr = A.Fake<IManager>();
|
||||||
|
var server = new IW4MServer(mgr,
|
||||||
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
|
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>(), A.Fake<IGameLogReaderFactory>(), A.Fake<IMetaService>());
|
||||||
|
|
||||||
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>(), A.Fake<ApplicationConfiguration>());
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>(), A.Fake<ApplicationConfiguration>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
|
|
||||||
@ -46,7 +55,13 @@ namespace ApplicationTests
|
|||||||
[Test]
|
[Test]
|
||||||
public void LogFileReplay()
|
public void LogFileReplay()
|
||||||
{
|
{
|
||||||
var server = _serviceProvider.GetRequiredService<IW4MServer>();
|
var mgr = A.Fake<IManager>();
|
||||||
|
A.CallTo(() => mgr.GetLogger(A<long>.Ignored)).Returns(logger);
|
||||||
|
|
||||||
|
var server = new IW4MServer(mgr,
|
||||||
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
|
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>(), A.Fake<IGameLogReaderFactory>(), A.Fake<IMetaService>());
|
||||||
|
|
||||||
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>(), A.Fake<ApplicationConfiguration>());
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>(), A.Fake<ApplicationConfiguration>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
|
|
||||||
@ -55,6 +70,7 @@ namespace ApplicationTests
|
|||||||
foreach (string line in log)
|
foreach (string line in log)
|
||||||
{
|
{
|
||||||
var e = parser.GenerateGameEvent(line);
|
var e = parser.GenerateGameEvent(line);
|
||||||
|
server.Logger.WriteInfo($"{e.GameTime}");
|
||||||
if (e.Origin != null)
|
if (e.Origin != null)
|
||||||
{
|
{
|
||||||
e.Origin.CurrentServer = server;
|
e.Origin.CurrentServer = server;
|
||||||
|
@ -6,6 +6,7 @@ using FakeItEasy;
|
|||||||
using IW4MAdmin.Application.EventParsers;
|
using IW4MAdmin.Application.EventParsers;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using IW4MAdmin.Plugins.Stats.Models;
|
using IW4MAdmin.Plugins.Stats.Models;
|
||||||
|
using IW4MAdmin.Application.Helpers;
|
||||||
using IW4MAdmin.Plugins.Stats.Config;
|
using IW4MAdmin.Plugins.Stats.Config;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
@ -16,7 +17,6 @@ using System.Threading.Tasks;
|
|||||||
using Stats.Helpers;
|
using Stats.Helpers;
|
||||||
using Stats.Dtos;
|
using Stats.Dtos;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
@ -35,15 +35,19 @@ namespace ApplicationTests
|
|||||||
handlerFactory = A.Fake<IConfigurationHandlerFactory>();
|
handlerFactory = A.Fake<IConfigurationHandlerFactory>();
|
||||||
|
|
||||||
serviceProvider = new ServiceCollection()
|
serviceProvider = new ServiceCollection()
|
||||||
.BuildBase()
|
|
||||||
.AddSingleton(A.Fake<IConfigurationHandler<StatsConfiguration>>())
|
|
||||||
.AddSingleton<StatsResourceQueryHelper>()
|
.AddSingleton<StatsResourceQueryHelper>()
|
||||||
.AddSingleton(new ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 })
|
.BuildBase()
|
||||||
.AddSingleton<StatManager>()
|
|
||||||
.AddSingleton<IW4MAdmin.Plugins.Stats.Plugin>()
|
.AddSingleton<IW4MAdmin.Plugins.Stats.Plugin>()
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
|
|
||||||
contextFactory = serviceProvider.GetRequiredService<IDatabaseContextFactory>();
|
contextFactory = serviceProvider.GetRequiredService<IDatabaseContextFactory>();
|
||||||
|
|
||||||
|
void testLog(string msg) => Console.WriteLine(msg);
|
||||||
|
|
||||||
|
A.CallTo(() => logger.WriteError(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
|
A.CallTo(() => logger.WriteWarning(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
|
A.CallTo(() => logger.WriteInfo(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
|
A.CallTo(() => logger.WriteDebug(A<string>.Ignored)).Invokes((string msg) => testLog(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -62,7 +66,13 @@ namespace ApplicationTests
|
|||||||
A.CallTo(() => handlerFactory.GetConfigurationHandler<StatsConfiguration>(A<string>.Ignored))
|
A.CallTo(() => handlerFactory.GetConfigurationHandler<StatsConfiguration>(A<string>.Ignored))
|
||||||
.Returns(config);
|
.Returns(config);
|
||||||
|
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
A.CallTo(() => mgr.GetLogger(A<long>.Ignored))
|
||||||
|
.Returns(logger);
|
||||||
|
|
||||||
|
var server = new IW4MServer(mgr,
|
||||||
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
|
A.Fake<ITranslationLookup>(),
|
||||||
|
A.Fake<IRConConnectionFactory>(), A.Fake<IGameLogReaderFactory>(), A.Fake<IMetaService>());
|
||||||
|
|
||||||
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>(), A.Fake<ApplicationConfiguration>());
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>(), A.Fake<ApplicationConfiguration>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
@ -125,8 +135,8 @@ namespace ApplicationTests
|
|||||||
public async Task Test_ConcurrentCallsToUpdateStatHistoryDoesNotCauseException()
|
public async Task Test_ConcurrentCallsToUpdateStatHistoryDoesNotCauseException()
|
||||||
{
|
{
|
||||||
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
var configHandler = serviceProvider.GetRequiredService<IConfigurationHandler<StatsConfiguration>>();
|
var configHandler = A.Fake<IConfigurationHandler<StatsConfiguration>>();
|
||||||
var mgr = serviceProvider.GetRequiredService<StatManager>();
|
var mgr = new StatManager(serviceProvider.GetRequiredService<IManager>(), serviceProvider.GetRequiredService<IDatabaseContextFactory>(), configHandler);
|
||||||
var target = ClientGenerators.CreateDatabaseClient();
|
var target = ClientGenerators.CreateDatabaseClient();
|
||||||
target.CurrentServer = server;
|
target.CurrentServer = server;
|
||||||
|
|
||||||
@ -138,11 +148,10 @@ namespace ApplicationTests
|
|||||||
|
|
||||||
var dbFactory = serviceProvider.GetRequiredService<IDatabaseContextFactory>();
|
var dbFactory = serviceProvider.GetRequiredService<IDatabaseContextFactory>();
|
||||||
var db = dbFactory.CreateContext(true);
|
var db = dbFactory.CreateContext(true);
|
||||||
var efServer = new EFServer()
|
db.Set<EFServer>().Add(new EFServer()
|
||||||
{
|
{
|
||||||
EndPoint = server.EndPoint.ToString()
|
EndPoint = server.EndPoint.ToString()
|
||||||
};
|
});
|
||||||
db.Set<EFServer>().Add(efServer);
|
|
||||||
|
|
||||||
db.Clients.Add(target);
|
db.Clients.Add(target);
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
@ -152,10 +161,6 @@ namespace ApplicationTests
|
|||||||
var stats = target.GetAdditionalProperty<EFClientStatistics>("ClientStats");
|
var stats = target.GetAdditionalProperty<EFClientStatistics>("ClientStats");
|
||||||
|
|
||||||
await mgr.UpdateStatHistory(target, stats);
|
await mgr.UpdateStatHistory(target, stats);
|
||||||
|
|
||||||
db.Clients.Remove(target);
|
|
||||||
db.Set<EFServer>().Remove(efServer);
|
|
||||||
await db.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region QUERY_HELPER
|
#region QUERY_HELPER
|
||||||
@ -163,7 +168,7 @@ namespace ApplicationTests
|
|||||||
public async Task Test_StatsQueryHelper_Get()
|
public async Task Test_StatsQueryHelper_Get()
|
||||||
{
|
{
|
||||||
var queryHelper = serviceProvider.GetRequiredService<StatsResourceQueryHelper>();
|
var queryHelper = serviceProvider.GetRequiredService<StatsResourceQueryHelper>();
|
||||||
await using var context = contextFactory.CreateContext();
|
using var context = contextFactory.CreateContext();
|
||||||
|
|
||||||
var server = new EFServer() { ServerId = 1 };
|
var server = new EFServer() { ServerId = 1 };
|
||||||
var stats = new EFClientStatistics()
|
var stats = new EFClientStatistics()
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using WebfrontCore.Controllers.API.Dtos;
|
using WebfrontCore.Controllers.API.Dtos;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace WebfrontCore.Controllers.API
|
namespace WebfrontCore.Controllers.API
|
||||||
{
|
{
|
||||||
@ -21,7 +20,7 @@ namespace WebfrontCore.Controllers.API
|
|||||||
private readonly IResourceQueryHelper<FindClientRequest, FindClientResult> _clientQueryHelper;
|
private readonly IResourceQueryHelper<FindClientRequest, FindClientResult> _clientQueryHelper;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public ClientController(ILogger<ClientController> logger, IResourceQueryHelper<FindClientRequest, FindClientResult> clientQueryHelper)
|
public ClientController(ILogger logger, IResourceQueryHelper<FindClientRequest, FindClientResult> clientQueryHelper)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_clientQueryHelper = clientQueryHelper;
|
_clientQueryHelper = clientQueryHelper;
|
||||||
@ -54,7 +53,8 @@ namespace WebfrontCore.Controllers.API
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(e, "Failed to retrieve clients with query - {@request}", request);
|
_logger.WriteWarning($"Failed to retrieve clients with query - {request.ToDebugString()}");
|
||||||
|
_logger.WriteDebug(e.GetExceptionInfo());
|
||||||
|
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse()
|
return StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse()
|
||||||
{
|
{
|
||||||
|
@ -171,7 +171,7 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
var meta = await ProfileMetaListViewComponent.GetClientMeta(_metaService, metaFilterType, Client.Level, request);
|
var meta = await ProfileMetaListViewComponent.GetClientMeta(_metaService, metaFilterType, Client.Level, request);
|
||||||
|
|
||||||
if (!meta.Any())
|
if (meta.Count() == 0)
|
||||||
{
|
{
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
@ -3,22 +3,19 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace WebfrontCore.Controllers
|
namespace WebfrontCore.Controllers
|
||||||
{
|
{
|
||||||
public class HomeController : BaseController
|
public class HomeController : BaseController
|
||||||
{
|
{
|
||||||
private readonly ITranslationLookup _translationLookup;
|
private readonly ITranslationLookup _translationLookup;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public HomeController(ILogger<HomeController> logger, IManager manager, ITranslationLookup translationLookup) : base(manager)
|
public HomeController(IManager manager, ITranslationLookup translationLookup) : base(manager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
_translationLookup = translationLookup;
|
_translationLookup = translationLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +43,10 @@ namespace WebfrontCore.Controllers
|
|||||||
public IActionResult Error()
|
public IActionResult Error()
|
||||||
{
|
{
|
||||||
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
|
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
|
||||||
_logger.LogError("[Webfront] {path} {message} {@exception}", exceptionFeature.Path, exceptionFeature.Error.Message, exceptionFeature.Error);
|
Manager.GetLogger(0).WriteError($"[Webfront] {exceptionFeature.Error.Message}");
|
||||||
|
Manager.GetLogger(0).WriteDebug(exceptionFeature.Path);
|
||||||
|
Manager.GetLogger(0).WriteDebug(exceptionFeature.Error.StackTrace);
|
||||||
|
|
||||||
ViewBag.Description = Localization["WEBFRONT_ERROR_DESC"];
|
ViewBag.Description = Localization["WEBFRONT_ERROR_DESC"];
|
||||||
ViewBag.Title = Localization["WEBFRONT_ERROR_TITLE"];
|
ViewBag.Title = Localization["WEBFRONT_ERROR_TITLE"];
|
||||||
return View(exceptionFeature.Error);
|
return View(exceptionFeature.Error);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|
||||||
|
|
||||||
namespace WebfrontCore.Middleware
|
namespace WebfrontCore.Middleware
|
||||||
{
|
{
|
||||||
@ -21,7 +22,7 @@ namespace WebfrontCore.Middleware
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="nextRequest"></param>
|
/// <param name="nextRequest"></param>
|
||||||
/// <param name="whitelistedIps">list of textual ip addresses</param>
|
/// <param name="whitelistedIps">list of textual ip addresses</param>
|
||||||
public IPWhitelist(RequestDelegate nextRequest, ILogger<IPWhitelist> logger, string[] whitelistedIps)
|
public IPWhitelist(RequestDelegate nextRequest, ILogger logger, string[] whitelistedIps)
|
||||||
{
|
{
|
||||||
_whitelistedIps = whitelistedIps.Select(_ip => System.Net.IPAddress.Parse(_ip).GetAddressBytes()).ToArray();
|
_whitelistedIps = whitelistedIps.Select(_ip => System.Net.IPAddress.Parse(_ip).GetAddressBytes()).ToArray();
|
||||||
_nextRequest = nextRequest;
|
_nextRequest = nextRequest;
|
||||||
@ -30,21 +31,21 @@ namespace WebfrontCore.Middleware
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
var isAllowed = true;
|
bool isAlllowed = true;
|
||||||
|
|
||||||
if (_whitelistedIps.Length > 0)
|
if (_whitelistedIps.Length > 0)
|
||||||
{
|
{
|
||||||
isAllowed = _whitelistedIps.Any(_ip => _ip.SequenceEqual(context.Connection.RemoteIpAddress.GetAddressBytes()));
|
isAlllowed = _whitelistedIps.Any(_ip => _ip.SequenceEqual(context.Connection.RemoteIpAddress.GetAddressBytes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAllowed)
|
if (isAlllowed)
|
||||||
{
|
{
|
||||||
await _nextRequest.Invoke(context);
|
await _nextRequest.Invoke(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Blocking HTTP request from {ipAddress}", context.Connection.RemoteIpAddress);
|
_logger.WriteInfo($"Blocking HTTP request from {context.Connection.RemoteIpAddress.ToString()}");
|
||||||
context.Abort();
|
context.Abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,11 +79,11 @@ namespace WebfrontCore
|
|||||||
});
|
});
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
/*mvcBuilder = mvcBuilder.AddRazorRuntimeCompilation();
|
mvcBuilder = mvcBuilder.AddRazorRuntimeCompilation();
|
||||||
services.Configure<RazorViewEngineOptions>(_options =>
|
services.Configure<RazorViewEngineOptions>(_options =>
|
||||||
{
|
{
|
||||||
_options.ViewLocationFormats.Add(@"/Views/Plugins/{1}/{0}" + RazorViewEngine.ViewExtension);
|
_options.ViewLocationFormats.Add(@"/Views/Plugins/{1}/{0}" + RazorViewEngine.ViewExtension);
|
||||||
});*/
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
foreach (var asm in pluginAssemblies())
|
foreach (var asm in pluginAssemblies())
|
||||||
@ -103,6 +103,13 @@ namespace WebfrontCore
|
|||||||
options.LoginPath = "/";
|
options.LoginPath = "/";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
services.AddLogging(_builder =>
|
||||||
|
{
|
||||||
|
_builder.AddDebug();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
services.AddSingleton(Program.Manager);
|
services.AddSingleton(Program.Manager);
|
||||||
services.AddSingleton<IResourceQueryHelper<ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>();
|
services.AddSingleton<IResourceQueryHelper<ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>();
|
||||||
services.AddTransient<IValidator<FindClientRequest>, FindClientRequestValidator>();
|
services.AddTransient<IValidator<FindClientRequest>, FindClientRequestValidator>();
|
||||||
@ -114,6 +121,7 @@ namespace WebfrontCore
|
|||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IDatabaseContextFactory>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IDatabaseContextFactory>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IAuditInformationRepository>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IAuditInformationRepository>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService<ITranslationLookup>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetService<ITranslationLookup>());
|
||||||
|
services.AddSingleton(Program.ApplicationServiceProvider.GetService<SharedLibraryCore.Interfaces.ILogger>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IEnumerable<IManagerCommand>>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IEnumerable<IManagerCommand>>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IMetaService>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IMetaService>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetService<ApplicationConfiguration>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetService<ApplicationConfiguration>());
|
||||||
@ -144,7 +152,7 @@ namespace WebfrontCore
|
|||||||
|
|
||||||
if (Program.Manager.GetApplicationSettings().Configuration().EnableWebfrontConnectionWhitelist)
|
if (Program.Manager.GetApplicationSettings().Configuration().EnableWebfrontConnectionWhitelist)
|
||||||
{
|
{
|
||||||
app.UseMiddleware<IPWhitelist>(Program.ApplicationServiceProvider.GetService<ILogger<IPWhitelist>>(), manager.GetApplicationSettings().Configuration().WebfrontConnectionWhitelist);
|
app.UseMiddleware<IPWhitelist>(manager.GetLogger(0), manager.GetApplicationSettings().Configuration().WebfrontConnectionWhitelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
@ -14,7 +14,7 @@ namespace WebfrontCore.ViewComponents
|
|||||||
var penalties = await Program.Manager.GetPenaltyService().GetRecentPenalties(PENALTY_COUNT, offset, showOnly, ignoreAutomated);
|
var penalties = await Program.Manager.GetPenaltyService().GetRecentPenalties(PENALTY_COUNT, offset, showOnly, ignoreAutomated);
|
||||||
penalties = User.Identity.IsAuthenticated ? penalties : penalties.Where(p => !p.Sensitive).ToList();
|
penalties = User.Identity.IsAuthenticated ? penalties : penalties.Where(p => !p.Sensitive).ToList();
|
||||||
|
|
||||||
return View("~/Views/Penalty/PenaltyInfoList.cshtml", penalties);
|
return View("_List", penalties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
@model IList<SharedLibraryCore.Dtos.PlayerInfo>
|
@model List<SharedLibraryCore.Dtos.PlayerInfo>
|
||||||
@{
|
@{
|
||||||
var loc = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex;
|
var loc = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (Model.ActivePenalty != null && (Model.ActivePenalty.Type != EFPenalty.PenaltyType.Flag || ViewBag.Authorized))
|
@if (Model.ActivePenalty != null)
|
||||||
{
|
{
|
||||||
<div class="font-weight-bold h4 mb-0 penalties-color-@Model.ActivePenalty.Type.ToString().ToLower()">
|
<div class="font-weight-bold h4 mb-0 penalties-color-@Model.ActivePenalty.Type.ToString().ToLower()">
|
||||||
@foreach (var result in Utilities.SplitTranslationTokens(translationKey))
|
@foreach (var result in Utilities.SplitTranslationTokens(translationKey))
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user