1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-09 23:00:57 -05:00

Misc Qodana cleanups

This commit is contained in:
Amos
2024-07-02 23:05:47 +01:00
committed by Ayymoss
parent e94a0ae691
commit f2b273b878
13 changed files with 150 additions and 154 deletions

View File

@ -47,7 +47,10 @@ 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>();
[Obsolete("Use Microsoft.Extensions.Logging.ILogger instead")]
public ObsoleteLogger Logger => _serviceProvider.GetRequiredService<ObsoleteLogger>(); // TODO: Deprecate this.
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; }
@ -55,6 +58,7 @@ namespace IW4MAdmin.Application
public IList<IRConParser> AdditionalRConParsers { get; } public IList<IRConParser> AdditionalRConParsers { get; }
public IList<IEventParser> AdditionalEventParsers { get; } public IList<IEventParser> AdditionalEventParsers { get; }
public IList<Func<GameEvent, bool>> CommandInterceptors { get; set; } = public IList<Func<GameEvent, bool>> CommandInterceptors { get; set; } =
new List<Func<GameEvent, bool>>(); new List<Func<GameEvent, bool>>();
public ITokenAuthentication TokenAuthenticator { get; } public ITokenAuthentication TokenAuthenticator { get; }
@ -90,13 +94,15 @@ namespace IW4MAdmin.Application
private readonly ApplicationConfiguration _appConfig; private readonly ApplicationConfiguration _appConfig;
public ConcurrentDictionary<long, GameEvent> ProcessingEvents { get; } = new(); public ConcurrentDictionary<long, GameEvent> ProcessingEvents { get; } = new();
public ApplicationManager(ILogger<ApplicationManager> logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands, public ApplicationManager(ILogger<ApplicationManager> 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,
ICoreEventHandler coreEventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, ICoreEventHandler coreEventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory,
IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver, ClientService clientService, IServiceProvider serviceProvider, IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver, ClientService clientService,
ChangeHistoryService changeHistoryService, ApplicationConfiguration appConfig, PenaltyService penaltyService, IAlertManager alertManager, IInteractionRegistration interactionRegistration, IEnumerable<IPluginV2> v2PLugins, IServiceProvider serviceProvider, ChangeHistoryService changeHistoryService, ApplicationConfiguration appConfig, PenaltyService penaltyService,
IAlertManager alertManager, IInteractionRegistration interactionRegistration, IEnumerable<IPluginV2> v2PLugins,
ConfigurationWatcher watcher) ConfigurationWatcher watcher)
{ {
MiddlewareActionHandler = actionHandler; MiddlewareActionHandler = actionHandler;
@ -302,41 +308,48 @@ namespace IW4MAdmin.Application
ExternalIPAddress = await Utilities.GetExternalIP(); ExternalIPAddress = await Utilities.GetExternalIP();
#region DATABASE #region DATABASE
_logger.LogInformation("Beginning database migration sync"); _logger.LogInformation("Beginning database migration sync");
Console.WriteLine(_translationLookup["MANAGER_MIGRATION_START"]); Console.WriteLine(_translationLookup["MANAGER_MIGRATION_START"]);
await ContextSeed.Seed(_serviceProvider.GetRequiredService<IDatabaseContextFactory>(), _isRunningTokenSource.Token); await ContextSeed.Seed(_serviceProvider.GetRequiredService<IDatabaseContextFactory>(), _isRunningTokenSource.Token);
await DatabaseHousekeeping.RemoveOldRatings(_serviceProvider.GetRequiredService<IDatabaseContextFactory>(), _isRunningTokenSource.Token); await DatabaseHousekeeping.RemoveOldRatings(_serviceProvider.GetRequiredService<IDatabaseContextFactory>(),
_isRunningTokenSource.Token);
_logger.LogInformation("Finished database migration sync"); _logger.LogInformation("Finished database migration sync");
Console.WriteLine(_translationLookup["MANAGER_MIGRATION_END"]); Console.WriteLine(_translationLookup["MANAGER_MIGRATION_END"]);
#endregion #endregion
#region EVENTS #region EVENTS
IGameServerEventSubscriptions.ServerValueRequested += OnServerValueRequested; IGameServerEventSubscriptions.ServerValueRequested += OnServerValueRequested;
IGameServerEventSubscriptions.ServerValueSetRequested += OnServerValueSetRequested; IGameServerEventSubscriptions.ServerValueSetRequested += OnServerValueSetRequested;
IGameServerEventSubscriptions.ServerCommandExecuteRequested += OnServerCommandExecuteRequested; IGameServerEventSubscriptions.ServerCommandExecuteRequested += OnServerCommandExecuteRequested;
await IManagementEventSubscriptions.InvokeLoadAsync(this, CancellationToken); await IManagementEventSubscriptions.InvokeLoadAsync(this, CancellationToken);
# endregion # endregion
#region PLUGINS #region PLUGINS
foreach (var plugin in Plugins) foreach (var plugin in Plugins)
{ {
try try
{ {
if (plugin is ScriptPlugin scriptPlugin && !plugin.IsParser) if (plugin is ScriptPlugin scriptPlugin && !plugin.IsParser)
{ {
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver, await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver,
_serviceProvider.GetService<IConfigurationHandlerV2<ScriptPluginConfiguration>>()); _serviceProvider.GetService<IConfigurationHandlerV2<ScriptPluginConfiguration>>());
scriptPlugin.Watcher.Changed += async (sender, e) => scriptPlugin.Watcher.Changed += async (sender, e) =>
{ {
try try
{ {
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver, await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver,
_serviceProvider.GetService<IConfigurationHandlerV2<ScriptPluginConfiguration>>()); _serviceProvider.GetService<IConfigurationHandlerV2<ScriptPluginConfiguration>>());
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_ERROR"].FormatExt(scriptPlugin.Name)); Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_ERROR"]
.FormatExt(scriptPlugin.Name));
_logger.LogError(ex, "Could not properly load plugin {plugin}", scriptPlugin.Name); _logger.LogError(ex, "Could not properly load plugin {plugin}", scriptPlugin.Name);
} }
}; };
@ -353,16 +366,18 @@ namespace IW4MAdmin.Application
_logger.LogError(ex, $"{_translationLookup["SERVER_ERROR_PLUGIN"]} {plugin.Name}"); _logger.LogError(ex, $"{_translationLookup["SERVER_ERROR_PLUGIN"]} {plugin.Name}");
} }
} }
#endregion #endregion
#region CONFIG #region CONFIG
// copy over default config if it doesn't exist // copy over default config if it doesn't exist
if (!_appConfig.Servers?.Any() ?? true) if (!_appConfig.Servers?.Any() ?? true)
{ {
var defaultHandler = new BaseConfigurationHandler<DefaultSettings>("DefaultSettings"); var defaultHandler = new BaseConfigurationHandler<DefaultSettings>("DefaultSettings");
await defaultHandler.BuildAsync(); await defaultHandler.BuildAsync();
var defaultConfig = defaultHandler.Configuration(); var defaultConfig = defaultHandler.Configuration();
_appConfig.AutoMessages = defaultConfig.AutoMessages; _appConfig.AutoMessages = defaultConfig.AutoMessages;
_appConfig.GlobalRules = defaultConfig.GlobalRules; _appConfig.GlobalRules = defaultConfig.GlobalRules;
_appConfig.DisallowedClientNames = defaultConfig.DisallowedClientNames; _appConfig.DisallowedClientNames = defaultConfig.DisallowedClientNames;
@ -385,8 +400,9 @@ namespace IW4MAdmin.Application
serverConfig.AddEventParser(parser); serverConfig.AddEventParser(parser);
} }
_appConfig.Servers = _appConfig.Servers.Where(_servers => _servers != null).Append((ServerConfiguration)serverConfig.Generate()).ToArray(); _appConfig.Servers = _appConfig.Servers.Where(_servers => _servers != null)
} while (Utilities.PromptBool(_translationLookup["SETUP_SERVER_SAVE"])); .Append((ServerConfiguration)serverConfig.Generate()).ToArray();
} while (_translationLookup["SETUP_SERVER_SAVE"].PromptBool());
await ConfigHandler.Save(); await ConfigHandler.Save();
} }
@ -447,6 +463,7 @@ namespace IW4MAdmin.Application
serverConfig.ModifyParsers(); serverConfig.ModifyParsers();
} }
} }
await ConfigHandler.Save(); await ConfigHandler.Save();
} }
@ -456,7 +473,9 @@ namespace IW4MAdmin.Application
} }
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(_appConfig.CustomParserEncoding)
? _appConfig.CustomParserEncoding
: "windows-1252");
foreach (var parser in AdditionalRConParsers) foreach (var parser in AdditionalRConParsers)
{ {
@ -472,6 +491,7 @@ namespace IW4MAdmin.Application
#endregion #endregion
#region COMMANDS #region COMMANDS
if (await ClientSvc.HasOwnerAsync(_isRunningTokenSource.Token)) if (await ClientSvc.HasOwnerAsync(_isRunningTokenSource.Token))
{ {
_commands.RemoveAll(_cmd => _cmd.GetType() == typeof(OwnerCommand)); _commands.RemoveAll(_cmd => _cmd.GetType() == typeof(OwnerCommand));
@ -503,25 +523,28 @@ namespace IW4MAdmin.Application
{ {
continue; continue;
} }
cmdConfig.Commands.Add(cmd.CommandConfigNameForType(), cmdConfig.Commands.Add(cmd.CommandConfigNameForType(),
new CommandProperties new CommandProperties
{ {
Name = cmd.Name, Name = cmd.Name,
Alias = cmd.Alias, Alias = cmd.Alias,
MinimumPermission = cmd.Permission, MinimumPermission = cmd.Permission,
AllowImpersonation = cmd.AllowImpersonation, AllowImpersonation = cmd.AllowImpersonation,
SupportedGames = cmd.SupportedGames SupportedGames = cmd.SupportedGames
}); });
} }
_commandConfiguration.Set(cmdConfig); _commandConfiguration.Set(cmdConfig);
await _commandConfiguration.Save(); await _commandConfiguration.Save();
#endregion #endregion
_metaRegistration.Register(); _metaRegistration.Register();
await _alertManager.Initialize(); await _alertManager.Initialize();
#region CUSTOM_EVENTS #region CUSTOM_EVENTS
foreach (var customEvent in _customParserEvents.SelectMany(_events => _events.Events)) foreach (var customEvent in _customParserEvents.SelectMany(_events => _events.Events))
{ {
foreach (var parser in AdditionalEventParsers) foreach (var parser in AdditionalEventParsers)
@ -529,8 +552,9 @@ namespace IW4MAdmin.Application
parser.RegisterCustomEvent(customEvent.Item1, customEvent.Item2, customEvent.Item3); parser.RegisterCustomEvent(customEvent.Item1, customEvent.Item2, customEvent.Item3);
} }
} }
#endregion #endregion
Console.WriteLine(_translationLookup["MANAGER_COMMUNICATION_INFO"]); Console.WriteLine(_translationLookup["MANAGER_COMMUNICATION_INFO"]);
await InitializeServers(); await InitializeServers();
_watcher.Enable(); _watcher.Enable();
@ -540,46 +564,10 @@ namespace IW4MAdmin.Application
private async Task InitializeServers() private async Task InitializeServers()
{ {
var config = ConfigHandler.Configuration(); var config = ConfigHandler.Configuration();
int successServers = 0; var successServers = 0;
Exception lastException = null; Exception lastException = null;
async Task Init(ServerConfiguration Conf) await Task.WhenAll(config.Servers.Select(LocalInit).ToArray());
{
try
{
// todo: this might not always be an IW4MServer
var serverInstance = _serverInstanceFactory.CreateServer(Conf, this) as IW4MServer;
using (LogContext.PushProperty("Server", serverInstance!.ToString()))
{
_logger.LogInformation("Beginning server communication initialization");
await serverInstance.Initialize();
_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);
}
QueueEvent(new MonitorStartEvent
{
Server = serverInstance,
Source = this
});
successServers++;
}
catch (ServerException e)
{
Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_UNFIXABLE"].FormatExt($"[{Conf.IPAddress}:{Conf.Port}]"));
using (LogContext.PushProperty("Server", $"{Conf.IPAddress}:{Conf.Port}"))
{
_logger.LogError(e, "Unexpected exception occurred during initialization");
}
lastException = e;
}
}
await Task.WhenAll(config.Servers.Select(c => Init(c)).ToArray());
if (successServers == 0) if (successServers == 0)
{ {
@ -593,23 +581,61 @@ namespace IW4MAdmin.Application
throw lastException; throw lastException;
} }
} }
return;
async Task LocalInit(ServerConfiguration conf)
{
try
{
// todo: this might not always be an IW4MServer
var serverInstance = _serverInstanceFactory.CreateServer(conf, this) as IW4MServer;
using (LogContext.PushProperty("Server", serverInstance!.ToString()))
{
_logger.LogInformation("Beginning server communication initialization");
await serverInstance.Initialize();
_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);
}
QueueEvent(new MonitorStartEvent
{
Server = serverInstance,
Source = this
});
successServers++;
}
catch (ServerException e)
{
Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_UNFIXABLE"]
.FormatExt($"[{conf.IPAddress}:{conf.Port}]"));
using (LogContext.PushProperty("Server", $"{conf.IPAddress}:{conf.Port}"))
{
_logger.LogError(e, "Unexpected exception occurred during initialization");
}
lastException = e;
}
}
} }
public async Task Start() public async Task Start()
{ {
_eventHandlerTokenSource = new CancellationTokenSource(); _eventHandlerTokenSource = new CancellationTokenSource();
var eventHandlerThread = new Thread(() => var eventHandlerThread = new Thread(() => { _coreEventHandler.StartProcessing(_eventHandlerTokenSource.Token); })
{
_coreEventHandler.StartProcessing(_eventHandlerTokenSource.Token);
})
{ {
Name = nameof(CoreEventHandler) Name = nameof(CoreEventHandler)
}; };
eventHandlerThread.Start(); eventHandlerThread.Start();
await UpdateServerStates(); await UpdateServerStates();
_eventHandlerTokenSource.Cancel(); await _eventHandlerTokenSource.CancelAsync();
eventHandlerThread.Join(); eventHandlerThread.Join();
} }
@ -636,7 +662,7 @@ namespace IW4MAdmin.Application
{ {
IsRestartRequested = true; IsRestartRequested = true;
await Stop(); await Stop();
using var subscriptionTimeoutToken = new CancellationTokenSource(); using var subscriptionTimeoutToken = new CancellationTokenSource();
subscriptionTimeoutToken.CancelAfter(Utilities.DefaultCommandTimeout); subscriptionTimeoutToken.CancelAfter(Utilities.DefaultCommandTimeout);
@ -645,10 +671,10 @@ namespace IW4MAdmin.Application
IGameEventSubscriptions.ClearEventInvocations(); IGameEventSubscriptions.ClearEventInvocations();
IGameServerEventSubscriptions.ClearEventInvocations(); IGameServerEventSubscriptions.ClearEventInvocations();
IManagementEventSubscriptions.ClearEventInvocations(); IManagementEventSubscriptions.ClearEventInvocations();
_isRunningTokenSource.Dispose(); _isRunningTokenSource.Dispose();
_isRunningTokenSource = new CancellationTokenSource(); _isRunningTokenSource = new CancellationTokenSource();
_eventHandlerTokenSource.Dispose(); _eventHandlerTokenSource.Dispose();
_eventHandlerTokenSource = new CancellationTokenSource(); _eventHandlerTokenSource = new CancellationTokenSource();
} }
@ -670,10 +696,10 @@ namespace IW4MAdmin.Application
return _servers.SelectMany(s => s.Clients).ToList().Where(p => p != null).ToList(); return _servers.SelectMany(s => s.Clients).ToList().Where(p => p != null).ToList();
} }
public EFClient FindActiveClient(EFClient client) => client.ClientNumber < 0 ? public EFClient FindActiveClient(EFClient client) => client.ClientNumber < 0
GetActiveClients() ? GetActiveClients()
.FirstOrDefault(c => c.NetworkId == client.NetworkId && c.GameName == client.GameName) ?? client : .FirstOrDefault(c => c.NetworkId == client.NetworkId && c.GameName == client.GameName) ?? client
client; : client;
public ClientService GetClientService() public ClientService GetClientService()
{ {
@ -699,7 +725,7 @@ namespace IW4MAdmin.Application
{ {
_coreEventHandler.QueueEvent(this, coreEvent); _coreEventHandler.QueueEvent(this, coreEvent);
} }
public IPageList GetPageList() public IPageList GetPageList()
{ {
return PageList; return PageList;
@ -715,7 +741,8 @@ namespace IW4MAdmin.Application
public IEventParser GenerateDynamicEventParser(string name) public IEventParser GenerateDynamicEventParser(string name)
{ {
return new DynamicEventParser(_parserRegexFactory, _logger, ConfigHandler.Configuration(), _serviceProvider.GetRequiredService<IGameScriptEventFactory>()) return new DynamicEventParser(_parserRegexFactory, _logger, ConfigHandler.Configuration(),
_serviceProvider.GetRequiredService<IGameScriptEventFactory>())
{ {
Name = name Name = name
}; };
@ -748,7 +775,7 @@ namespace IW4MAdmin.Application
public void RemoveCommandByName(string commandName) => _commands.RemoveAll(_command => _command.Name == commandName); public void RemoveCommandByName(string commandName) => _commands.RemoveAll(_command => _command.Name == commandName);
public IAlertManager AlertManager => _alertManager; public IAlertManager AlertManager => _alertManager;
private async Task OnServerValueRequested(ServerValueRequestEvent requestEvent, CancellationToken token) private async Task OnServerValueRequested(ServerValueRequestEvent requestEvent, CancellationToken token)
{ {
if (requestEvent.Server is not IW4MServer server) if (requestEvent.Server is not IW4MServer server)
@ -768,7 +795,7 @@ namespace IW4MAdmin.Application
using var timeoutTokenSource = new CancellationTokenSource(); using var timeoutTokenSource = new CancellationTokenSource();
using var linkedTokenSource = using var linkedTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, token); CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, token);
if (requestEvent.TimeoutMs is not null) if (requestEvent.TimeoutMs is not null)
{ {
timeoutTokenSource.CancelAfter(requestEvent.TimeoutMs.Value); timeoutTokenSource.CancelAfter(requestEvent.TimeoutMs.Value);

View File

@ -22,16 +22,14 @@ namespace IW4MAdmin.Application.Commands
RequiresTarget = false; RequiresTarget = false;
} }
public override Task ExecuteAsync(GameEvent gameEvent) public override async Task ExecuteAsync(GameEvent gameEvent)
{ {
var clientList = gameEvent.Owner.GetClientsAsList() var clientList = gameEvent.Owner.GetClientsAsList()
.Select(client => .Select(client =>
$"[(Color::Accent){client.ClientPermission.Name}(Color::White){(string.IsNullOrEmpty(client.Tag) ? "" : $" {client.Tag}")}(Color::White)][(Color::Yellow)#{client.ClientNumber}(Color::White)] {client.Name}") $"[(Color::Accent){client.ClientPermission.Name}(Color::White){(string.IsNullOrEmpty(client.Tag) ? "" : $" {client.Tag}")}(Color::White)][(Color::Yellow)#{client.ClientNumber}(Color::White)] {client.Name}")
.ToArray(); .ToArray();
gameEvent.Origin.TellAsync(clientList, gameEvent.Owner.Manager.CancellationToken); await gameEvent.Origin.TellAsync(clientList, gameEvent.Owner.Manager.CancellationToken);
return Task.CompletedTask;
} }
} }
} }

View File

@ -11,26 +11,15 @@ namespace IW4MAdmin.Application.Factories
/// <summary> /// <summary>
/// implementation of IGameServerInstanceFactory /// implementation of IGameServerInstanceFactory
/// </summary> /// </summary>
internal class GameServerInstanceFactory : IGameServerInstanceFactory /// <param name="translationLookup"></param>
/// <param name="metaService"></param>
/// <param name="serviceProvider"></param>
internal class GameServerInstanceFactory(
ITranslationLookup translationLookup,
IMetaServiceV2 metaService,
IServiceProvider serviceProvider)
: IGameServerInstanceFactory
{ {
private readonly ITranslationLookup _translationLookup;
private readonly IMetaServiceV2 _metaService;
private readonly IServiceProvider _serviceProvider;
/// <summary>
/// base constructor
/// </summary>
/// <param name="translationLookup"></param>
/// <param name="rconConnectionFactory"></param>
public GameServerInstanceFactory(ITranslationLookup translationLookup,
IMetaServiceV2 metaService,
IServiceProvider serviceProvider)
{
_translationLookup = translationLookup;
_metaService = metaService;
_serviceProvider = serviceProvider;
}
/// <summary> /// <summary>
/// creates an IW4MServer instance /// creates an IW4MServer instance
/// </summary> /// </summary>
@ -40,9 +29,9 @@ namespace IW4MAdmin.Application.Factories
public Server CreateServer(ServerConfiguration config, IManager manager) public Server CreateServer(ServerConfiguration config, IManager manager)
{ {
return new IW4MServer(config, return new IW4MServer(config,
_serviceProvider.GetRequiredService<CommandConfiguration>(), _translationLookup, _metaService, serviceProvider.GetRequiredService<CommandConfiguration>(), translationLookup, metaService,
_serviceProvider, _serviceProvider.GetRequiredService<IClientNoticeMessageFormatter>(), serviceProvider, serviceProvider.GetRequiredService<IClientNoticeMessageFormatter>(),
_serviceProvider.GetRequiredService<ILookupCache<EFServer>>()); serviceProvider.GetRequiredService<ILookupCache<EFServer>>());
} }
} }
} }

View File

@ -213,7 +213,7 @@ namespace IW4MAdmin.Application
var masterCommunicator = serviceProvider.GetRequiredService<IMasterCommunication>(); var masterCommunicator = serviceProvider.GetRequiredService<IMasterCommunication>();
var webfrontLifetime = serviceProvider.GetRequiredService<IHostApplicationLifetime>(); var webfrontLifetime = serviceProvider.GetRequiredService<IHostApplicationLifetime>();
using var onWebfrontErrored = new ManualResetEventSlim(); using var onWebfrontErrored = new ManualResetEventSlim();
var webfrontTask = _serverManager.GetApplicationSettings().Configuration().EnableWebFront var webfrontTask = _serverManager.GetApplicationSettings().Configuration().EnableWebFront
? WebfrontCore.Program.GetWebHostTask(_serverManager.CancellationToken).ContinueWith(continuation => ? WebfrontCore.Program.GetWebHostTask(_serverManager.CancellationToken).ContinueWith(continuation =>
{ {
@ -226,9 +226,9 @@ namespace IW4MAdmin.Application
continuation.Exception?.InnerException?.Message); continuation.Exception?.InnerException?.Message);
logger.LogDebug(continuation.Exception, "Unable to start webfront task"); logger.LogDebug(continuation.Exception, "Unable to start webfront task");
onWebfrontErrored.Set(); // ReSharper disable once AccessToDisposedClosure
onWebfrontErrored.Set(); // TODO: Check if this dispose warning is a roslyn issue.
}) })
: Task.CompletedTask; : Task.CompletedTask;

View File

@ -52,14 +52,11 @@ namespace IW4MAdmin.Application.Misc
await _onSaving.WaitAsync(); await _onSaving.WaitAsync();
await using var fileStream = File.OpenRead(FileName); await using var fileStream = File.OpenRead(FileName);
_configuration = await JsonSerializer.DeserializeAsync<T>(fileStream, _serializerOptions); _configuration = await JsonSerializer.DeserializeAsync<T>(fileStream, _serializerOptions);
await fileStream.DisposeAsync();
} }
catch (FileNotFoundException) catch (FileNotFoundException)
{ {
_configuration = default; _configuration = default;
} }
catch (Exception e) catch (Exception e)
{ {
throw new ConfigurationException("Could not load configuration") throw new ConfigurationException("Could not load configuration")
@ -82,12 +79,9 @@ namespace IW4MAdmin.Application.Misc
try try
{ {
await _onSaving.WaitAsync(); await _onSaving.WaitAsync();
await using var fileStream = File.Create(FileName); await using var fileStream = File.Create(FileName);
await JsonSerializer.SerializeAsync(fileStream, _configuration, _serializerOptions); await JsonSerializer.SerializeAsync(fileStream, _configuration, _serializerOptions);
await fileStream.DisposeAsync();
} }
finally finally
{ {
if (_onSaving.CurrentCount == 0) if (_onSaving.CurrentCount == 0)

View File

@ -4,7 +4,7 @@ using ILogger = SharedLibraryCore.Interfaces.ILogger;
namespace IW4MAdmin.Application.Misc namespace IW4MAdmin.Application.Misc
{ {
[Obsolete] [Obsolete("Use Microsoft.Extensions.Logging.ILogger instead")]
public class Logger : ILogger public class Logger : ILogger
{ {
private readonly Microsoft.Extensions.Logging.ILogger _logger; private readonly Microsoft.Extensions.Logging.ILogger _logger;

View File

@ -7,16 +7,10 @@ using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace IW4MAdmin.Application.Misc namespace IW4MAdmin.Application.Misc
{ {
class MiddlewareActionHandler : IMiddlewareActionHandler internal class MiddlewareActionHandler(ILogger<MiddlewareActionHandler> logger) : IMiddlewareActionHandler
{ {
private readonly IDictionary<string, IList<object>> _actions; private readonly Dictionary<string, IList<object>> _actions = new();
private readonly ILogger _logger; private readonly ILogger _logger = logger;
public MiddlewareActionHandler(ILogger<MiddlewareActionHandler> logger)
{
_actions = new Dictionary<string, IList<object>>();
_logger = logger;
}
/// <summary> /// <summary>
/// Executes the action with the given name /// Executes the action with the given name
@ -27,23 +21,19 @@ namespace IW4MAdmin.Application.Misc
/// <returns></returns> /// <returns></returns>
public async Task<T> Execute<T>(T value, string name = null) public async Task<T> Execute<T>(T value, string name = null)
{ {
string key = string.IsNullOrEmpty(name) ? typeof(T).ToString() : name; var key = string.IsNullOrEmpty(name) ? typeof(T).ToString() : name;
if (_actions.ContainsKey(key)) if (!_actions.TryGetValue(key, out var action1)) return value;
foreach (var action in action1)
{ {
foreach (var action in _actions[key]) try
{ {
try value = await ((IMiddlewareAction<T>)action).Invoke(value);
{ }
value = await ((IMiddlewareAction<T>)action).Invoke(value); catch (Exception e)
} {
catch (Exception e) _logger.LogWarning(e, "Failed to invoke middleware action {Name}", name);
{
_logger.LogWarning(e, "Failed to invoke middleware action {name}", name);
}
} }
return value;
} }
return value; return value;
@ -58,16 +48,15 @@ namespace IW4MAdmin.Application.Misc
/// <param name="name">Name of action</param> /// <param name="name">Name of action</param>
public void Register<T>(T actionType, IMiddlewareAction<T> action, string name = null) public void Register<T>(T actionType, IMiddlewareAction<T> action, string name = null)
{ {
string key = string.IsNullOrEmpty(name) ? typeof(T).ToString() : name; var key = string.IsNullOrEmpty(name) ? typeof(T).ToString() : name;
if (_actions.ContainsKey(key)) if (_actions.TryGetValue(key, out var action1))
{ {
_actions[key].Add(action); action1.Add(action);
} }
else else
{ {
_actions.Add(key, new[] { action }); _actions.Add(key, [action]);
} }
} }
} }

View File

@ -201,7 +201,7 @@ namespace Integrations.Cod
DontFragment = false, DontFragment = false,
Ttl = 100, Ttl = 100,
ExclusiveAddressUse = true, ExclusiveAddressUse = true,
}) }!) // Suppressing "Initialize object properties inside the 'using' statement to ensure that the object is disposed if an exception is thrown during initialization"
{ {
if (!token.IsCancellationRequested) if (!token.IsCancellationRequested)
{ {

View File

@ -107,9 +107,7 @@ namespace SharedLibraryCore.Helpers
private static int ParseVersion(string input) private static int ParseVersion(string input)
{ {
int version; if (!int.TryParse(input, out var version))
if (!int.TryParse(input, out version))
{ {
throw new FormatException( throw new FormatException(
"buildNumber string was not in a correct format"); "buildNumber string was not in a correct format");
@ -160,4 +158,4 @@ namespace SharedLibraryCore.Helpers
} }
} }
} }
} }

View File

@ -2,7 +2,7 @@
namespace SharedLibraryCore.Interfaces namespace SharedLibraryCore.Interfaces
{ {
[Obsolete] [Obsolete("Use Microsoft.Extensions.Logging.ILogger instead")]
public interface ILogger public interface ILogger
{ {
void WriteVerbose(string msg); void WriteVerbose(string msg);
@ -12,4 +12,4 @@ namespace SharedLibraryCore.Interfaces
void WriteError(string msg); void WriteError(string msg);
void WriteAssert(bool condition, string msg); void WriteAssert(bool condition, string msg);
} }
} }

View File

@ -799,6 +799,8 @@ namespace SharedLibraryCore
} }
public static async Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName, public static async Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName,
// Suppressing as older plugins could reference old signature.
// ReSharper disable once MethodOverloadWithOptionalParameter
T fallbackValue = default, CancellationToken token = default) T fallbackValue = default, CancellationToken token = default)
{ {
return await server.RconParser.GetDvarAsync(server.RemoteConnection, dvarName, fallbackValue, token); return await server.RconParser.GetDvarAsync(server.RemoteConnection, dvarName, fallbackValue, token);
@ -818,9 +820,8 @@ namespace SharedLibraryCore
var mappedKey = server.RconParser.GetOverrideDvarName(dvarName); var mappedKey = server.RconParser.GetOverrideDvarName(dvarName);
var defaultValue = server.RconParser.GetDefaultDvarValue<T>(mappedKey) ?? overrideDefault; var defaultValue = server.RconParser.GetDefaultDvarValue<T>(mappedKey) ?? overrideDefault;
var foundKey = infoResponse?.Keys var foundKey = (infoResponse?.Keys ?? Enumerable.Empty<string>())
.Where(_key => new[] { mappedKey, dvarName, infoResponseName ?? dvarName }.Contains(_key)) .FirstOrDefault(key => new[] { mappedKey, dvarName, infoResponseName ?? dvarName }.Contains(key));
.FirstOrDefault();
if (!string.IsNullOrEmpty(foundKey)) if (!string.IsNullOrEmpty(foundKey))
{ {

View File

@ -129,7 +129,7 @@
.OrderBy(rating => rating.CreatedDateTime) .OrderBy(rating => rating.CreatedDateTime)
.Select(rating => new PerformanceHistory { Performance = rating.PerformanceMetric, OccurredAt = rating.CreatedDateTime }); .Select(rating => new PerformanceHistory { Performance = rating.PerformanceMetric, OccurredAt = rating.CreatedDateTime });
if (performance != null && performance != Model.Ratings.FirstOrDefault().PerformanceMetric) if (performance != null && !Model.Ratings.FirstOrDefault().PerformanceMetric.Equals(performance))
{ {
performanceHistory = performanceHistory.Append(new PerformanceHistory { Performance = performance.Value, OccurredAt = Model.Ratings.FirstOrDefault()?.CreatedDateTime ?? DateTime.UtcNow }); performanceHistory = performanceHistory.Append(new PerformanceHistory { Performance = performance.Value, OccurredAt = Model.Ratings.FirstOrDefault()?.CreatedDateTime ?? DateTime.UtcNow });
} }

View File

@ -89,7 +89,7 @@
else if (hasLinkedParent(property)) else if (hasLinkedParent(property))
{ {
<div id="@($"{property.Name}_content")" class="@(linkedPropertyNames.Length == 0 ? "hide" : "hide") bg-dark pl-3 pr-3 pb-2"> <div id="@($"{property.Name}_content")" class="hide bg-dark pl-3 pr-3 pb-2">
@if (linkedPropertyNames.Length == 0) @if (linkedPropertyNames.Length == 0)
{ {
@Html.Label(property.Name, null, new {@class = "mt-2 d-block"}) @Html.Label(property.Name, null, new {@class = "mt-2 d-block"})