Compare commits
22 Commits
2022.01.27
...
2022.02.02
Author | SHA1 | Date | |
---|---|---|---|
b7a76cc4a2 | |||
261da918c7 | |||
2ed5e00bcb | |||
6ca94f8da8 | |||
3b532cf1f7 | |||
40966ed74d | |||
45eacabc28 | |||
0b02b7627a | |||
fc3a24ca17 | |||
209cb6cdd0 | |||
cfd4296f5c | |||
b275fbaced | |||
b2a3625288 | |||
0d3e2cb0bc | |||
505a2c4c2d | |||
8730a3fab8 | |||
3539101a40 | |||
7ccdee7d1b | |||
f4b160b735 | |||
73036dc1c7 | |||
6cfcce23cc | |||
8649b0efe9 |
@ -355,10 +355,10 @@ namespace IW4MAdmin.Application
|
|||||||
// 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 defaultConfig = new BaseConfigurationHandler<DefaultSettings>("DefaultSettings").Configuration();
|
var defaultHandler = new BaseConfigurationHandler<DefaultSettings>("DefaultSettings");
|
||||||
//ConfigHandler.Set((ApplicationConfiguration)new ApplicationConfiguration().Generate());
|
await defaultHandler.BuildAsync();
|
||||||
//var newConfig = ConfigHandler.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;
|
||||||
|
@ -47,6 +47,10 @@ echo making start scripts
|
|||||||
@(echo @echo off && echo @title IW4MAdmin && echo set DOTNET_CLI_TELEMETRY_OPTOUT=1 && echo dotnet Lib\IW4MAdmin.dll && echo pause) > "%PublishDir%\StartIW4MAdmin.cmd"
|
@(echo @echo off && echo @title IW4MAdmin && echo set DOTNET_CLI_TELEMETRY_OPTOUT=1 && echo dotnet Lib\IW4MAdmin.dll && echo pause) > "%PublishDir%\StartIW4MAdmin.cmd"
|
||||||
@(echo #!/bin/bash&& echo export DOTNET_CLI_TELEMETRY_OPTOUT=1&& echo dotnet Lib/IW4MAdmin.dll) > "%PublishDir%\StartIW4MAdmin.sh"
|
@(echo #!/bin/bash&& echo export DOTNET_CLI_TELEMETRY_OPTOUT=1&& echo dotnet Lib/IW4MAdmin.dll) > "%PublishDir%\StartIW4MAdmin.sh"
|
||||||
|
|
||||||
|
echo copying update scripts
|
||||||
|
copy "%SourceDir%\DeploymentFiles\UpdateIW4MAdmin.ps1" "%PublishDir%\UpdateIW4MAdmin.ps1"
|
||||||
|
copy "%SourceDir%\DeploymentFiles\UpdateIW4MAdmin.sh" "%PublishDir%\UpdateIW4MAdmin.sh"
|
||||||
|
|
||||||
echo moving front-end library dependencies
|
echo moving front-end library dependencies
|
||||||
if not exist "%PublishDir%\wwwroot\font" mkdir "%PublishDir%\wwwroot\font"
|
if not exist "%PublishDir%\wwwroot\font" mkdir "%PublishDir%\wwwroot\font"
|
||||||
move "WebfrontCore\wwwroot\lib\open-iconic\font\fonts\*.*" "%PublishDir%\wwwroot\font\"
|
move "WebfrontCore\wwwroot\lib\open-iconic\font\fonts\*.*" "%PublishDir%\wwwroot\font\"
|
||||||
|
@ -94,7 +94,7 @@ namespace IW4MAdmin.Application.Extensions
|
|||||||
postgresqlOptions =>
|
postgresqlOptions =>
|
||||||
{
|
{
|
||||||
postgresqlOptions.EnableRetryOnFailure();
|
postgresqlOptions.EnableRetryOnFailure();
|
||||||
postgresqlOptions.SetPostgresVersion(new Version("9.4"));
|
postgresqlOptions.SetPostgresVersion(new Version("12.9"));
|
||||||
})
|
})
|
||||||
.UseLoggerFactory(sp.GetRequiredService<ILoggerFactory>()).Options);
|
.UseLoggerFactory(sp.GetRequiredService<ILoggerFactory>()).Options);
|
||||||
return services;
|
return services;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using IW4MAdmin.Application.Misc;
|
using System.Threading.Tasks;
|
||||||
|
using IW4MAdmin.Application.Misc;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Factories
|
namespace IW4MAdmin.Application.Factories
|
||||||
@ -17,7 +18,17 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IConfigurationHandler<T> GetConfigurationHandler<T>(string name) where T : IBaseConfiguration
|
public IConfigurationHandler<T> GetConfigurationHandler<T>(string name) where T : IBaseConfiguration
|
||||||
{
|
{
|
||||||
return new BaseConfigurationHandler<T>(name);
|
var handler = new BaseConfigurationHandler<T>(name);
|
||||||
|
handler.BuildAsync().Wait();
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<IConfigurationHandler<T>> GetConfigurationHandlerAsync<T>(string name) where T : IBaseConfiguration
|
||||||
|
{
|
||||||
|
var handler = new BaseConfigurationHandler<T>(name);
|
||||||
|
await handler.BuildAsync();
|
||||||
|
return handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -25,7 +26,6 @@ using Data.Models;
|
|||||||
using Data.Models.Server;
|
using Data.Models.Server;
|
||||||
using IW4MAdmin.Application.Commands;
|
using IW4MAdmin.Application.Commands;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using SharedLibraryCore.Formatting;
|
|
||||||
using static Data.Models.Client.EFClient;
|
using static Data.Models.Client.EFClient;
|
||||||
|
|
||||||
namespace IW4MAdmin
|
namespace IW4MAdmin
|
||||||
@ -355,7 +355,7 @@ namespace IW4MAdmin
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = _serviceProvider.GetRequiredService<IDatabaseContextFactory>();
|
var factory = _serviceProvider.GetRequiredService<IDatabaseContextFactory>();
|
||||||
await using var context = factory.CreateContext();
|
await using var context = factory.CreateContext(enableTracking: false);
|
||||||
|
|
||||||
var messageCount = await context.InboxMessages
|
var messageCount = await context.InboxMessages
|
||||||
.CountAsync(msg => msg.DestinationClientId == E.Origin.ClientId && !msg.IsDelivered);
|
.CountAsync(msg => msg.DestinationClientId == E.Origin.ClientId && !msg.IsDelivered);
|
||||||
@ -1076,19 +1076,26 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ResolvedIpEndPoint = new IPEndPoint((await Dns.GetHostAddressesAsync(IP)).First(), Port);
|
ResolvedIpEndPoint =
|
||||||
|
new IPEndPoint(
|
||||||
|
(await Dns.GetHostAddressesAsync(IP)).First(address =>
|
||||||
|
address.AddressFamily == AddressFamily.InterNetwork), Port);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ServerLogger.LogWarning(ex, "Could not resolve hostname or IP for RCon connection {IP}:{Port}", IP, Port);
|
ServerLogger.LogWarning(ex, "Could not resolve hostname or IP for RCon connection {IP}:{Port}", IP, Port);
|
||||||
ResolvedIpEndPoint = new IPEndPoint(IPAddress.Parse(IP), Port);
|
ResolvedIpEndPoint = new IPEndPoint(IPAddress.Parse(IP), Port);
|
||||||
}
|
}
|
||||||
|
|
||||||
RconParser = Manager.AdditionalRConParsers
|
RconParser = Manager.AdditionalRConParsers
|
||||||
.FirstOrDefault(_parser => _parser.Version == ServerConfig.RConParserVersion);
|
.FirstOrDefault(parser =>
|
||||||
|
parser.Version == ServerConfig.RConParserVersion ||
|
||||||
|
parser.Name == ServerConfig.RConParserVersion);
|
||||||
|
|
||||||
EventParser = Manager.AdditionalEventParsers
|
EventParser = Manager.AdditionalEventParsers
|
||||||
.FirstOrDefault(_parser => _parser.Version == ServerConfig.EventParserVersion);
|
.FirstOrDefault(parser =>
|
||||||
|
parser.Version == ServerConfig.EventParserVersion ||
|
||||||
|
parser.Name == ServerConfig.RConParserVersion);
|
||||||
|
|
||||||
RconParser ??= Manager.AdditionalRConParsers[0];
|
RconParser ??= Manager.AdditionalRConParsers[0];
|
||||||
EventParser ??= Manager.AdditionalEventParsers[0];
|
EventParser ??= Manager.AdditionalEventParsers[0];
|
||||||
@ -1105,7 +1112,7 @@ namespace IW4MAdmin
|
|||||||
GameName = RconParser.GameName;
|
GameName = RconParser.GameName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version?.Value?.Length != 0)
|
if (version.Value?.Length != 0)
|
||||||
{
|
{
|
||||||
var matchedRconParser = Manager.AdditionalRConParsers.FirstOrDefault(_parser => _parser.Version == version.Value);
|
var matchedRconParser = Manager.AdditionalRConParsers.FirstOrDefault(_parser => _parser.Version == version.Value);
|
||||||
RconParser.Configuration = matchedRconParser != null ? matchedRconParser.Configuration : RconParser.Configuration;
|
RconParser.Configuration = matchedRconParser != null ? matchedRconParser.Configuration : RconParser.Configuration;
|
||||||
|
@ -34,6 +34,7 @@ using IW4MAdmin.Plugins.Stats.Client.Abstractions;
|
|||||||
using IW4MAdmin.Plugins.Stats.Client;
|
using IW4MAdmin.Plugins.Stats.Client;
|
||||||
using Stats.Client.Abstractions;
|
using Stats.Client.Abstractions;
|
||||||
using Stats.Client;
|
using Stats.Client;
|
||||||
|
using Stats.Config;
|
||||||
using Stats.Helpers;
|
using Stats.Helpers;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
@ -41,9 +42,9 @@ namespace IW4MAdmin.Application
|
|||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
public static BuildNumber Version { get; } = BuildNumber.Parse(Utilities.GetVersionAsString());
|
public static BuildNumber Version { get; } = BuildNumber.Parse(Utilities.GetVersionAsString());
|
||||||
public static ApplicationManager ServerManager;
|
private static ApplicationManager _serverManager;
|
||||||
private static Task ApplicationTask;
|
private static Task _applicationTask;
|
||||||
private static ServiceProvider serviceProvider;
|
private static ServiceProvider _serviceProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// entrypoint of the application
|
/// entrypoint of the application
|
||||||
@ -75,10 +76,10 @@ namespace IW4MAdmin.Application
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private static async void OnCancelKey(object sender, ConsoleCancelEventArgs e)
|
private static async void OnCancelKey(object sender, ConsoleCancelEventArgs e)
|
||||||
{
|
{
|
||||||
ServerManager?.Stop();
|
_serverManager?.Stop();
|
||||||
if (ApplicationTask != null)
|
if (_applicationTask != null)
|
||||||
{
|
{
|
||||||
await ApplicationTask;
|
await _applicationTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +93,6 @@ namespace IW4MAdmin.Application
|
|||||||
ITranslationLookup translationLookup = null;
|
ITranslationLookup translationLookup = null;
|
||||||
var logger = BuildDefaultLogger<Program>(new ApplicationConfiguration());
|
var logger = BuildDefaultLogger<Program>(new ApplicationConfiguration());
|
||||||
Utilities.DefaultLogger = logger;
|
Utilities.DefaultLogger = logger;
|
||||||
IServiceCollection services = null;
|
|
||||||
logger.LogInformation("Begin IW4MAdmin startup. Version is {Version} {@Args}", Version, args);
|
logger.LogInformation("Begin IW4MAdmin startup. Version is {Version} {@Args}", Version, args);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -102,18 +102,18 @@ namespace IW4MAdmin.Application
|
|||||||
ConfigurationMigration.CheckDirectories();
|
ConfigurationMigration.CheckDirectories();
|
||||||
ConfigurationMigration.RemoveObsoletePlugins20210322();
|
ConfigurationMigration.RemoveObsoletePlugins20210322();
|
||||||
logger.LogDebug("Configuring services...");
|
logger.LogDebug("Configuring services...");
|
||||||
services = ConfigureServices(args);
|
var services = await 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>();
|
||||||
|
|
||||||
ApplicationTask = RunApplicationTasksAsync(logger, services);
|
_applicationTask = RunApplicationTasksAsync(logger, services);
|
||||||
var tasks = new[]
|
var tasks = new[]
|
||||||
{
|
{
|
||||||
versionChecker.CheckVersion(),
|
versionChecker.CheckVersion(),
|
||||||
ServerManager.Init(),
|
_serverManager.Init(),
|
||||||
ApplicationTask
|
_applicationTask
|
||||||
};
|
};
|
||||||
|
|
||||||
await Task.WhenAll(tasks);
|
await Task.WhenAll(tasks);
|
||||||
@ -160,12 +160,12 @@ namespace IW4MAdmin.Application
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ServerManager.IsRestartRequested)
|
if (_serverManager.IsRestartRequested)
|
||||||
{
|
{
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
await serviceProvider.DisposeAsync();
|
await _serviceProvider.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -174,11 +174,11 @@ namespace IW4MAdmin.Application
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static async Task RunApplicationTasksAsync(ILogger logger, IServiceCollection services)
|
private static async Task RunApplicationTasksAsync(ILogger logger, IServiceCollection services)
|
||||||
{
|
{
|
||||||
var webfrontTask = ServerManager.GetApplicationSettings().Configuration().EnableWebFront
|
var webfrontTask = _serverManager.GetApplicationSettings().Configuration().EnableWebFront
|
||||||
? WebfrontCore.Program.Init(ServerManager, serviceProvider, services, ServerManager.CancellationToken)
|
? WebfrontCore.Program.Init(_serverManager, _serviceProvider, services, _serverManager.CancellationToken)
|
||||||
: Task.CompletedTask;
|
: Task.CompletedTask;
|
||||||
|
|
||||||
var collectionService = serviceProvider.GetRequiredService<IServerDataCollector>();
|
var collectionService = _serviceProvider.GetRequiredService<IServerDataCollector>();
|
||||||
|
|
||||||
// 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
|
||||||
@ -190,10 +190,10 @@ namespace IW4MAdmin.Application
|
|||||||
var tasks = new[]
|
var tasks = new[]
|
||||||
{
|
{
|
||||||
webfrontTask,
|
webfrontTask,
|
||||||
ServerManager.Start(),
|
_serverManager.Start(),
|
||||||
serviceProvider.GetRequiredService<IMasterCommunication>()
|
_serviceProvider.GetRequiredService<IMasterCommunication>()
|
||||||
.RunUploadStatus(ServerManager.CancellationToken),
|
.RunUploadStatus(_serverManager.CancellationToken),
|
||||||
collectionService.BeginCollectionAsync(cancellationToken: ServerManager.CancellationToken)
|
collectionService.BeginCollectionAsync(cancellationToken: _serverManager.CancellationToken)
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.LogDebug("Starting webfront and input tasks");
|
logger.LogDebug("Starting webfront and input tasks");
|
||||||
@ -215,14 +215,19 @@ namespace IW4MAdmin.Application
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string lastCommand;
|
|
||||||
EFClient origin = null;
|
EFClient origin = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (!ServerManager.CancellationToken.IsCancellationRequested)
|
while (!_serverManager.CancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
lastCommand = await Console.In.ReadLineAsync();
|
if (!_serverManager.IsInitialized)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastCommand = await Console.In.ReadLineAsync();
|
||||||
|
|
||||||
if (lastCommand == null)
|
if (lastCommand == null)
|
||||||
{
|
{
|
||||||
@ -238,12 +243,12 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Command,
|
Type = GameEvent.EventType.Command,
|
||||||
Data = lastCommand,
|
Data = lastCommand,
|
||||||
Origin = origin ??= Utilities.IW4MAdminClient(ServerManager.Servers.FirstOrDefault()),
|
Origin = origin ??= Utilities.IW4MAdminClient(_serverManager.Servers.FirstOrDefault()),
|
||||||
Owner = ServerManager.Servers[0]
|
Owner = _serverManager.Servers[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerManager.AddEvent(gameEvent);
|
_serverManager.AddEvent(gameEvent);
|
||||||
await gameEvent.WaitAsync(Utilities.DefaultCommandTimeout, ServerManager.CancellationToken);
|
await gameEvent.WaitAsync(Utilities.DefaultCommandTimeout, _serverManager.CancellationToken);
|
||||||
Console.Write('>');
|
Console.Write('>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,9 +278,9 @@ namespace IW4MAdmin.Application
|
|||||||
// 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()
|
||||||
.Concat(typeof(Program).Assembly.GetTypes().Where(type => type.Namespace == "IW4MAdmin.Application.Commands"))
|
.Concat(typeof(Program).Assembly.GetTypes().Where(type => type.Namespace == "IW4MAdmin.Application.Commands"))
|
||||||
.Where(_command => _command.BaseType == typeof(Command)))
|
.Where(command => command.BaseType == typeof(Command)))
|
||||||
{
|
{
|
||||||
defaultLogger.LogDebug("Registered native command type {name}", commandType.Name);
|
defaultLogger.LogDebug("Registered native command type {Name}", commandType.Name);
|
||||||
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,23 +288,23 @@ namespace IW4MAdmin.Application
|
|||||||
var (plugins, commands, configurations) = pluginImporter.DiscoverAssemblyPluginImplementations();
|
var (plugins, commands, configurations) = pluginImporter.DiscoverAssemblyPluginImplementations();
|
||||||
foreach (var pluginType in plugins)
|
foreach (var pluginType in plugins)
|
||||||
{
|
{
|
||||||
defaultLogger.LogDebug("Registered plugin type {name}", pluginType.FullName);
|
defaultLogger.LogDebug("Registered plugin type {Name}", pluginType.FullName);
|
||||||
serviceCollection.AddSingleton(typeof(IPlugin), pluginType);
|
serviceCollection.AddSingleton(typeof(IPlugin), pluginType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the plugin commands
|
// register the plugin commands
|
||||||
foreach (var commandType in commands)
|
foreach (var commandType in commands)
|
||||||
{
|
{
|
||||||
defaultLogger.LogDebug("Registered plugin command type {name}", commandType.FullName);
|
defaultLogger.LogDebug("Registered plugin command type {Name}", commandType.FullName);
|
||||||
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var configurationType in configurations)
|
foreach (var configurationType in configurations)
|
||||||
{
|
{
|
||||||
defaultLogger.LogDebug("Registered plugin config type {name}", configurationType.Name);
|
defaultLogger.LogDebug("Registered plugin config type {Name}", configurationType.Name);
|
||||||
var configInstance = (IBaseConfiguration) Activator.CreateInstance(configurationType);
|
var configInstance = (IBaseConfiguration) Activator.CreateInstance(configurationType);
|
||||||
var handlerType = typeof(BaseConfigurationHandler<>).MakeGenericType(configurationType);
|
var handlerType = typeof(BaseConfigurationHandler<>).MakeGenericType(configurationType);
|
||||||
var handlerInstance = Activator.CreateInstance(handlerType, new[] {configInstance.Name()});
|
var handlerInstance = Activator.CreateInstance(handlerType, configInstance.Name());
|
||||||
var genericInterfaceType = typeof(IConfigurationHandler<>).MakeGenericType(configurationType);
|
var genericInterfaceType = typeof(IConfigurationHandler<>).MakeGenericType(configurationType);
|
||||||
|
|
||||||
serviceCollection.AddSingleton(genericInterfaceType, handlerInstance);
|
serviceCollection.AddSingleton(genericInterfaceType, handlerInstance);
|
||||||
@ -313,10 +318,10 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
// register any eventable types
|
// register any eventable types
|
||||||
foreach (var assemblyType in typeof(Program).Assembly.GetTypes()
|
foreach (var assemblyType in typeof(Program).Assembly.GetTypes()
|
||||||
.Where(_asmType => typeof(IRegisterEvent).IsAssignableFrom(_asmType))
|
.Where(asmType => typeof(IRegisterEvent).IsAssignableFrom(asmType))
|
||||||
.Union(plugins.SelectMany(_asm => _asm.Assembly.GetTypes())
|
.Union(plugins.SelectMany(asm => asm.Assembly.GetTypes())
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.Where(_asmType => typeof(IRegisterEvent).IsAssignableFrom(_asmType))))
|
.Where(asmType => typeof(IRegisterEvent).IsAssignableFrom(asmType))))
|
||||||
{
|
{
|
||||||
var instance = Activator.CreateInstance(assemblyType) as IRegisterEvent;
|
var instance = Activator.CreateInstance(assemblyType) as IRegisterEvent;
|
||||||
serviceCollection.AddSingleton(instance);
|
serviceCollection.AddSingleton(instance);
|
||||||
@ -329,7 +334,7 @@ namespace IW4MAdmin.Application
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the dependency injection services
|
/// Configures the dependency injection services
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static IServiceCollection ConfigureServices(string[] args)
|
private static async Task<IServiceCollection> ConfigureServices(string[] args)
|
||||||
{
|
{
|
||||||
// todo: this is a quick fix
|
// todo: this is a quick fix
|
||||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||||
@ -337,7 +342,13 @@ namespace IW4MAdmin.Application
|
|||||||
// setup the static resources (config/master api/translations)
|
// setup the static resources (config/master api/translations)
|
||||||
var serviceCollection = new ServiceCollection();
|
var serviceCollection = new ServiceCollection();
|
||||||
var appConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
|
var appConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
|
||||||
|
await appConfigHandler.BuildAsync();
|
||||||
var defaultConfigHandler = new BaseConfigurationHandler<DefaultSettings>("DefaultSettings");
|
var defaultConfigHandler = new BaseConfigurationHandler<DefaultSettings>("DefaultSettings");
|
||||||
|
await defaultConfigHandler.BuildAsync();
|
||||||
|
var commandConfigHandler = new BaseConfigurationHandler<CommandConfiguration>("CommandConfiguration");
|
||||||
|
await commandConfigHandler.BuildAsync();
|
||||||
|
var statsCommandHandler = new BaseConfigurationHandler<StatsConfiguration>();
|
||||||
|
await statsCommandHandler.BuildAsync();
|
||||||
var defaultConfig = defaultConfigHandler.Configuration();
|
var defaultConfig = defaultConfigHandler.Configuration();
|
||||||
var appConfig = appConfigHandler.Configuration();
|
var appConfig = appConfigHandler.Configuration();
|
||||||
var masterUri = Utilities.IsDevelopment
|
var masterUri = Utilities.IsDevelopment
|
||||||
@ -355,7 +366,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
appConfig = (ApplicationConfiguration) new ApplicationConfiguration().Generate();
|
appConfig = (ApplicationConfiguration) new ApplicationConfiguration().Generate();
|
||||||
appConfigHandler.Set(appConfig);
|
appConfigHandler.Set(appConfig);
|
||||||
appConfigHandler.Save().RunSynchronously();
|
await appConfigHandler.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// register override level names
|
// register override level names
|
||||||
@ -373,15 +384,14 @@ namespace IW4MAdmin.Application
|
|||||||
serviceCollection
|
serviceCollection
|
||||||
.AddBaseLogger(appConfig)
|
.AddBaseLogger(appConfig)
|
||||||
.AddSingleton(defaultConfig)
|
.AddSingleton(defaultConfig)
|
||||||
.AddSingleton<IServiceCollection>(_serviceProvider => serviceCollection)
|
.AddSingleton<IServiceCollection>(serviceCollection)
|
||||||
.AddSingleton<IConfigurationHandler<DefaultSettings>, BaseConfigurationHandler<DefaultSettings>>()
|
.AddSingleton<IConfigurationHandler<DefaultSettings>, BaseConfigurationHandler<DefaultSettings>>()
|
||||||
.AddSingleton((IConfigurationHandler<ApplicationConfiguration>) appConfigHandler)
|
.AddSingleton((IConfigurationHandler<ApplicationConfiguration>) appConfigHandler)
|
||||||
.AddSingleton(
|
.AddSingleton<IConfigurationHandler<CommandConfiguration>>(commandConfigHandler)
|
||||||
new BaseConfigurationHandler<CommandConfiguration>("CommandConfiguration") as
|
|
||||||
IConfigurationHandler<CommandConfiguration>)
|
|
||||||
.AddSingleton(appConfig)
|
.AddSingleton(appConfig)
|
||||||
.AddSingleton(_serviceProvider =>
|
.AddSingleton(statsCommandHandler.Configuration() ?? new StatsConfiguration())
|
||||||
_serviceProvider.GetRequiredService<IConfigurationHandler<CommandConfiguration>>()
|
.AddSingleton(serviceProvider =>
|
||||||
|
serviceProvider.GetRequiredService<IConfigurationHandler<CommandConfiguration>>()
|
||||||
.Configuration() ?? new CommandConfiguration())
|
.Configuration() ?? new CommandConfiguration())
|
||||||
.AddSingleton<IPluginImporter, PluginImporter>()
|
.AddSingleton<IPluginImporter, PluginImporter>()
|
||||||
.AddSingleton<IMiddlewareActionHandler, MiddlewareActionHandler>()
|
.AddSingleton<IMiddlewareActionHandler, MiddlewareActionHandler>()
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
using Newtonsoft.Json;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore;
|
|
||||||
using SharedLibraryCore.Exceptions;
|
using SharedLibraryCore.Exceptions;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Misc
|
namespace IW4MAdmin.Application.Misc
|
||||||
{
|
{
|
||||||
@ -15,19 +17,24 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
/// <typeparam name="T">base configuration type</typeparam>
|
/// <typeparam name="T">base configuration type</typeparam>
|
||||||
public class BaseConfigurationHandler<T> : IConfigurationHandler<T> where T : IBaseConfiguration
|
public class BaseConfigurationHandler<T> : IConfigurationHandler<T> where T : IBaseConfiguration
|
||||||
{
|
{
|
||||||
T _configuration;
|
private T _configuration;
|
||||||
private readonly SemaphoreSlim _onSaving;
|
private readonly SemaphoreSlim _onSaving;
|
||||||
|
private readonly JsonSerializerOptions _serializerOptions;
|
||||||
|
|
||||||
public BaseConfigurationHandler(string fn)
|
|
||||||
|
public BaseConfigurationHandler(string fileName)
|
||||||
{
|
{
|
||||||
|
_serializerOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
};
|
||||||
|
_serializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||||
_onSaving = new SemaphoreSlim(1, 1);
|
_onSaving = new SemaphoreSlim(1, 1);
|
||||||
FileName = Path.Join(Utilities.OperatingDirectory, "Configuration", $"{fn}.json");
|
FileName = Path.Join(Utilities.OperatingDirectory, "Configuration", $"{fileName}.json");
|
||||||
Build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseConfigurationHandler() : this(typeof(T).Name)
|
public BaseConfigurationHandler() : this(typeof(T).Name)
|
||||||
{
|
{
|
||||||
_onSaving = new SemaphoreSlim(1, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~BaseConfigurationHandler()
|
~BaseConfigurationHandler()
|
||||||
@ -37,12 +44,12 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
public string FileName { get; }
|
public string FileName { get; }
|
||||||
|
|
||||||
public void Build()
|
public async Task BuildAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var configContent = File.ReadAllText(FileName);
|
await using var fileStream = File.OpenRead(FileName);
|
||||||
_configuration = JsonConvert.DeserializeObject<T>(configContent);
|
_configuration = await JsonSerializer.DeserializeAsync<T>(fileStream, _serializerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (FileNotFoundException)
|
catch (FileNotFoundException)
|
||||||
@ -65,14 +72,9 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _onSaving.WaitAsync();
|
await _onSaving.WaitAsync();
|
||||||
var settings = new JsonSerializerSettings()
|
|
||||||
{
|
|
||||||
Formatting = Formatting.Indented
|
|
||||||
};
|
|
||||||
settings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
|
|
||||||
|
|
||||||
var appConfigJson = JsonConvert.SerializeObject(_configuration, settings);
|
await using var fileStream = File.Create(FileName);
|
||||||
await File.WriteAllTextAsync(FileName, appConfigJson);
|
await JsonSerializer.SerializeAsync(fileStream, _configuration, _serializerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
finally
|
||||||
|
@ -26,7 +26,8 @@ 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;
|
||||||
|
private static readonly TimeSpan Interval = TimeSpan.FromSeconds(30);
|
||||||
|
|
||||||
public MasterCommunication(ILogger<MasterCommunication> logger, ApplicationConfiguration appConfig, ITranslationLookup translationLookup, IMasterApi apiInstance, IManager manager)
|
public MasterCommunication(ILogger<MasterCommunication> logger, ApplicationConfiguration appConfig, ITranslationLookup translationLookup, IMasterApi apiInstance, IManager manager)
|
||||||
{
|
{
|
||||||
@ -97,7 +98,10 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await UploadStatus();
|
if (_manager.IsRunning)
|
||||||
|
{
|
||||||
|
await UploadStatus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -107,7 +111,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(30000, token);
|
await Task.Delay(Interval, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch
|
catch
|
||||||
@ -119,7 +123,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
private async Task UploadStatus()
|
private async Task UploadStatus()
|
||||||
{
|
{
|
||||||
if (firstHeartBeat)
|
if (_firstHeartBeat)
|
||||||
{
|
{
|
||||||
var token = await _apiInstance.Authenticate(new AuthenticationId
|
var token = await _apiInstance.Authenticate(new AuthenticationId
|
||||||
{
|
{
|
||||||
@ -153,7 +157,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
Response<ResultMessage> response = null;
|
Response<ResultMessage> response = null;
|
||||||
|
|
||||||
if (firstHeartBeat)
|
if (_firstHeartBeat)
|
||||||
{
|
{
|
||||||
response = await _apiInstance.AddInstance(instance);
|
response = await _apiInstance.AddInstance(instance);
|
||||||
}
|
}
|
||||||
@ -161,7 +165,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
response = await _apiInstance.UpdateInstance(instance.Id, instance);
|
response = await _apiInstance.UpdateInstance(instance.Id, instance);
|
||||||
firstHeartBeat = false;
|
_firstHeartBeat = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.ResponseMessage.StatusCode != System.Net.HttpStatusCode.OK)
|
if (response.ResponseMessage.StatusCode != System.Net.HttpStatusCode.OK)
|
||||||
|
@ -207,42 +207,30 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
public async Task<IEnumerable<IClientMeta>> GetRuntimeMeta(ClientPaginationRequest request)
|
public async Task<IEnumerable<IClientMeta>> GetRuntimeMeta(ClientPaginationRequest request)
|
||||||
{
|
{
|
||||||
var meta = new List<IClientMeta>();
|
var metas = await Task.WhenAll(_metaActions.Where(kvp => kvp.Key != MetaType.Information)
|
||||||
|
.Select(async kvp => await kvp.Value[0](request)));
|
||||||
|
|
||||||
foreach (var (type, actions) in _metaActions)
|
return metas.SelectMany(m => (IEnumerable<IClientMeta>)m)
|
||||||
{
|
.OrderByDescending(m => m.When)
|
||||||
// information is not listed chronologically
|
|
||||||
if (type != MetaType.Information)
|
|
||||||
{
|
|
||||||
var metaItems = await actions[0](request);
|
|
||||||
meta.AddRange(metaItems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return meta.OrderByDescending(_meta => _meta.When)
|
|
||||||
.Take(request.Count)
|
.Take(request.Count)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<T>> GetRuntimeMeta<T>(ClientPaginationRequest request, MetaType metaType) where T : IClientMeta
|
public async Task<IEnumerable<T>> GetRuntimeMeta<T>(ClientPaginationRequest request, MetaType metaType) where T : IClientMeta
|
||||||
{
|
{
|
||||||
IEnumerable<T> meta;
|
|
||||||
if (metaType == MetaType.Information)
|
if (metaType == MetaType.Information)
|
||||||
{
|
{
|
||||||
var allMeta = new List<T>();
|
var allMeta = new List<T>();
|
||||||
|
|
||||||
foreach (var individualMetaRegistration in _metaActions[metaType])
|
var completedMeta = await Task.WhenAll(_metaActions[metaType].Select(async individualMetaRegistration =>
|
||||||
{
|
(IEnumerable<T>)await individualMetaRegistration(request)));
|
||||||
allMeta.AddRange(await individualMetaRegistration(request));
|
|
||||||
}
|
allMeta.AddRange(completedMeta.SelectMany(meta => meta));
|
||||||
|
|
||||||
return ProcessInformationMeta(allMeta);
|
return ProcessInformationMeta(allMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
var meta = await _metaActions[metaType][0](request) as IEnumerable<T>;
|
||||||
{
|
|
||||||
meta = await _metaActions[metaType][0](request) as IEnumerable<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
@ -168,22 +168,26 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_scriptEngine.SetValue("_configHandler", new ScriptPluginConfigurationWrapper(Name, _scriptEngine));
|
|
||||||
await OnLoadAsync(manager);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (pluginObject.isParser)
|
if (pluginObject.isParser)
|
||||||
{
|
{
|
||||||
|
await OnLoadAsync(manager);
|
||||||
IsParser = true;
|
IsParser = true;
|
||||||
IEventParser eventParser = (IEventParser)_scriptEngine.GetValue("eventParser").ToObject();
|
var eventParser = (IEventParser)_scriptEngine.GetValue("eventParser").ToObject();
|
||||||
IRConParser rconParser = (IRConParser)_scriptEngine.GetValue("rconParser").ToObject();
|
var rconParser = (IRConParser)_scriptEngine.GetValue("rconParser").ToObject();
|
||||||
manager.AdditionalEventParsers.Add(eventParser);
|
manager.AdditionalEventParsers.Add(eventParser);
|
||||||
manager.AdditionalRConParsers.Add(rconParser);
|
manager.AdditionalRConParsers.Add(rconParser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (RuntimeBinderException) { }
|
catch (RuntimeBinderException)
|
||||||
|
{
|
||||||
|
var configWrapper = new ScriptPluginConfigurationWrapper(Name, _scriptEngine);
|
||||||
|
await configWrapper.InitializeAsync();
|
||||||
|
_scriptEngine.SetValue("_configHandler", configWrapper);
|
||||||
|
await OnLoadAsync(manager);
|
||||||
|
}
|
||||||
|
|
||||||
if (!firstRun)
|
if (!firstRun)
|
||||||
{
|
{
|
||||||
|
@ -12,19 +12,24 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
public class ScriptPluginConfigurationWrapper
|
public class ScriptPluginConfigurationWrapper
|
||||||
{
|
{
|
||||||
private readonly BaseConfigurationHandler<ScriptPluginConfiguration> _handler;
|
private readonly BaseConfigurationHandler<ScriptPluginConfiguration> _handler;
|
||||||
private readonly ScriptPluginConfiguration _config;
|
private ScriptPluginConfiguration _config;
|
||||||
private readonly string _pluginName;
|
private readonly string _pluginName;
|
||||||
private readonly Engine _scriptEngine;
|
private readonly Engine _scriptEngine;
|
||||||
|
|
||||||
public ScriptPluginConfigurationWrapper(string pluginName, Engine scriptEngine)
|
public ScriptPluginConfigurationWrapper(string pluginName, Engine scriptEngine)
|
||||||
{
|
{
|
||||||
_handler = new BaseConfigurationHandler<ScriptPluginConfiguration>("ScriptPluginSettings");
|
_handler = new BaseConfigurationHandler<ScriptPluginConfiguration>("ScriptPluginSettings");
|
||||||
_config = _handler.Configuration() ??
|
|
||||||
(ScriptPluginConfiguration) new ScriptPluginConfiguration().Generate();
|
|
||||||
_pluginName = pluginName;
|
_pluginName = pluginName;
|
||||||
_scriptEngine = scriptEngine;
|
_scriptEngine = scriptEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await _handler.BuildAsync();
|
||||||
|
_config = _handler.Configuration() ??
|
||||||
|
(ScriptPluginConfiguration) new ScriptPluginConfiguration().Generate();
|
||||||
|
}
|
||||||
|
|
||||||
private static int? AsInteger(double d)
|
private static int? AsInteger(double d)
|
||||||
{
|
{
|
||||||
return int.TryParse(d.ToString(CultureInfo.InvariantCulture), out var parsed) ? parsed : (int?) null;
|
return int.TryParse(d.ToString(CultureInfo.InvariantCulture), out var parsed) ? parsed : (int?) null;
|
||||||
@ -87,4 +92,4 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
return JsValue.FromObject(_scriptEngine, item);
|
return JsValue.FromObject(_scriptEngine, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ namespace Data.Context
|
|||||||
{
|
{
|
||||||
var link = new EFAliasLink();
|
var link = new EFAliasLink();
|
||||||
|
|
||||||
context.Clients.Add(new EFClient()
|
context.Clients.Add(new EFClient
|
||||||
{
|
{
|
||||||
Active = false,
|
Active = false,
|
||||||
Connections = 0,
|
Connections = 0,
|
||||||
@ -33,7 +33,7 @@ namespace Data.Context
|
|||||||
Masked = true,
|
Masked = true,
|
||||||
NetworkId = 0,
|
NetworkId = 0,
|
||||||
AliasLink = link,
|
AliasLink = link,
|
||||||
CurrentAlias = new EFAlias()
|
CurrentAlias = new EFAlias
|
||||||
{
|
{
|
||||||
Link = link,
|
Link = link,
|
||||||
Active = true,
|
Active = true,
|
||||||
@ -46,4 +46,4 @@ namespace Data.Context
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ namespace Data.Helpers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var context = _contextFactory.CreateContext();
|
await using var context = _contextFactory.CreateContext(false);
|
||||||
_cachedItems = await context.Set<T>().ToDictionaryAsync(item => item.Id);
|
_cachedItems = await context.Set<T>().ToDictionaryAsync(item => item.Id);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -111,4 +111,4 @@ namespace Data.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,10 @@ namespace Data.MigrationContext
|
|||||||
{
|
{
|
||||||
optionsBuilder.UseNpgsql(
|
optionsBuilder.UseNpgsql(
|
||||||
"Host=127.0.0.1;Database=IW4MAdmin_Migration;Username=postgres;Password=password;",
|
"Host=127.0.0.1;Database=IW4MAdmin_Migration;Username=postgres;Password=password;",
|
||||||
options => options.SetPostgresVersion(new Version("9.4")))
|
options => options.SetPostgresVersion(new Version("12.9")))
|
||||||
.EnableDetailedErrors(true)
|
.EnableDetailedErrors(true)
|
||||||
.EnableSensitiveDataLogging(true);
|
.EnableSensitiveDataLogging(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
// ReSharper disable CompareOfFloatsByEqualityOperator
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||||||
|
#pragma warning disable CS0659
|
||||||
|
|
||||||
namespace Data.Models
|
namespace Data.Models
|
||||||
{
|
{
|
||||||
@ -29,9 +30,7 @@ namespace Data.Models
|
|||||||
return $"({X}, {Y}, {Z})";
|
return $"({X}, {Y}, {Z})";
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS0659
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
#pragma warning restore CS0659
|
|
||||||
{
|
{
|
||||||
if (obj is Vector3 vec)
|
if (obj is Vector3 vec)
|
||||||
{
|
{
|
||||||
|
118
DeploymentFiles/UpdateIW4MAdmin.ps1
Normal file
118
DeploymentFiles/UpdateIW4MAdmin.ps1
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
param (
|
||||||
|
[Parameter(HelpMessage = "Do not prompt for any user input")]
|
||||||
|
[switch]$Silent = $False,
|
||||||
|
|
||||||
|
[Parameter(HelpMessage = "Clean unneeded files listed in _delete.txt after update")]
|
||||||
|
[switch]$Clean = $False,
|
||||||
|
|
||||||
|
[Parameter(HelpMessage = "Only update releases in the verified stream")]
|
||||||
|
[switch]$Verified = $False,
|
||||||
|
|
||||||
|
[Parameter(HelpMessage = "Directory to install to")]
|
||||||
|
[ValidateScript({
|
||||||
|
if (-Not($_ | Test-Path))
|
||||||
|
{
|
||||||
|
throw "File or folder does not exist"
|
||||||
|
} return $true
|
||||||
|
})]
|
||||||
|
[System.IO.FileInfo]$Directory
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Output "======================================="
|
||||||
|
Write-Output " IW4MAdmin Updater v1 "
|
||||||
|
Write-Output " by XERXES & RaidMax "
|
||||||
|
Write-Output "======================================="
|
||||||
|
|
||||||
|
$stopwatch = [system.diagnostics.stopwatch]::StartNew()
|
||||||
|
$repoName = "RaidMax/IW4M-Admin"
|
||||||
|
$assetPattern = "IW4MAdmin-20*.zip"
|
||||||
|
|
||||||
|
if ($Verified)
|
||||||
|
{
|
||||||
|
$releasesUri = "https://api.github.com/repos/$repoName/releases/latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$releasesUri = "https://api.github.com/repos/$repoName/releases"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Retrieving latest version info..."
|
||||||
|
|
||||||
|
$releaseInfo = (Invoke-WebRequest $releasesUri | ConvertFrom-Json) | Select -First 1
|
||||||
|
$asset = $releaseInfo.assets | Where-Object name -like $assetPattern | Select -First 1
|
||||||
|
$downloadUri = $asset.browser_download_url
|
||||||
|
$filename = Split-Path $downloadUri -leaf
|
||||||
|
|
||||||
|
Write-Output "The latest version is $( $releaseInfo.tag_name ) released $( $releaseInfo.published_at )"
|
||||||
|
|
||||||
|
if (!$Silent)
|
||||||
|
{
|
||||||
|
$stopwatch.Stop()
|
||||||
|
Write-Warning "All IW4MAdmin files will be updated. Your database and configuration will not be modified. Are you sure you want to continue?" -WarningAction Inquire
|
||||||
|
$stopwatch.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Downloading update. This might take a moment..."
|
||||||
|
|
||||||
|
$fileDownload = Invoke-WebRequest -Uri $downloadUri
|
||||||
|
if ($fileDownload.StatusDescription -ne "OK")
|
||||||
|
{
|
||||||
|
throw "Could not update IW4MAdmin. ($fileDownload.StatusDescription)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$remoteHash = $fileDownload.Headers['Content-MD5']
|
||||||
|
$decodedHash = [System.BitConverter]::ToString([System.Convert]::FromBase64String($remoteHash)).replace('-', '')
|
||||||
|
$directoryPath = Get-Location
|
||||||
|
$fullPath = "$directoryPath\$filename"
|
||||||
|
$outputFile = [System.IO.File]::Open($fullPath, 2)
|
||||||
|
$stream = [System.IO.BinaryWriter]::new($outputFile)
|
||||||
|
|
||||||
|
if ($Directory)
|
||||||
|
{
|
||||||
|
$outputDir = $Directory
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$outputDir = Get-Location
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$stream.Write($fileDownload.Content)
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
$stream.Dispose()
|
||||||
|
$outputFile.Dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
$localHash = (Get-FileHash -Path $fullPath -Algorithm MD5).Hash
|
||||||
|
|
||||||
|
if ($localHash -ne $decodedHash)
|
||||||
|
{
|
||||||
|
throw "Failed to update. File hashes don't match!"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Extracting $filename to $outputDir"
|
||||||
|
Expand-Archive -Path $fullPath -DestinationPath $outputDir -Force
|
||||||
|
|
||||||
|
if ($Clean)
|
||||||
|
{
|
||||||
|
Write-Output "Running post-update clean..."
|
||||||
|
$DeleteList = Get-Content -Path ./_delete.txt
|
||||||
|
ForEach ($file in $DeleteList)
|
||||||
|
{
|
||||||
|
Write-Output "Deleting $file"
|
||||||
|
Remove-Item -Path $file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Removing temporary files..."
|
||||||
|
Remove-Item -Force $fullPath
|
||||||
|
|
||||||
|
$stopwatch.Stop()
|
||||||
|
$executionTime = [math]::Round($stopwatch.Elapsed.TotalSeconds, 0)
|
||||||
|
|
||||||
|
Write-Output "Update completed successfully in $executionTime seconds!"
|
106
DeploymentFiles/UpdateIW4MAdmin.sh
Normal file
106
DeploymentFiles/UpdateIW4MAdmin.sh
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "======================================="
|
||||||
|
echo " IW4MAdmin Updater v1 "
|
||||||
|
echo "======================================="
|
||||||
|
|
||||||
|
while getopts scvd: flag
|
||||||
|
do
|
||||||
|
case "${flag}" in
|
||||||
|
s) silent='true';;
|
||||||
|
c) clean='true';;
|
||||||
|
v) verified='true';;
|
||||||
|
d) directory=${OPTARG};;
|
||||||
|
*) exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
start=$SECONDS
|
||||||
|
repoName="RaidMax/IW4M-Admin"
|
||||||
|
releaseUri="https://api.github.com/repos/$repoName/releases"
|
||||||
|
|
||||||
|
echo "Retrieving latest version info..."
|
||||||
|
|
||||||
|
if [ ! "$directory" ]
|
||||||
|
then
|
||||||
|
directory=$(pwd)
|
||||||
|
else
|
||||||
|
if [ ! -d "$directory" ]
|
||||||
|
then
|
||||||
|
mkdir "$directory"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$verified" ]
|
||||||
|
then
|
||||||
|
releaseUri="https://api.github.com/repos/$repoName/releases/latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
releaseInfo=$(curl -s "${releaseUri}")
|
||||||
|
downloadUri=$(echo "$releaseInfo" | grep "browser_download_url" | cut -d '"' -f 4"" | head -n1)
|
||||||
|
publishDate=$(echo "$releaseInfo"| grep "published_at" | cut -d '"' -f 4"" | head -n1)
|
||||||
|
releaseTitle=$(echo "$releaseInfo" | grep "tag_name" | cut -d '"' -f 4"" | head -n1)
|
||||||
|
filename=$(basename $downloadUri)
|
||||||
|
fullpath="$directory/$filename"
|
||||||
|
|
||||||
|
echo "The latest version is $releaseTitle released $publishDate"
|
||||||
|
|
||||||
|
if [[ ! "$silent" ]]
|
||||||
|
then
|
||||||
|
echo -e "\033[33mAll IW4MAdmin files will be updated.\033[0m"
|
||||||
|
echo -e "\033[33mYour database and configuration will not be modified.\033[0m"
|
||||||
|
read -p "Are you sure you want to continue [Y/N]? " -n 1 -r
|
||||||
|
echo
|
||||||
|
if ! [[ $REPLY =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Downloading update. This might take a moment..."
|
||||||
|
|
||||||
|
wget -q "$downloadUri" -O "$fullpath"
|
||||||
|
|
||||||
|
if [[ $? -ne 0 ]]
|
||||||
|
then
|
||||||
|
echo "Could not download update files!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Extracting $filename to $directory"
|
||||||
|
|
||||||
|
unzip -o -q "$fullpath" -d "$directory"
|
||||||
|
|
||||||
|
if [[ $? -ne 0 ]]
|
||||||
|
then
|
||||||
|
echo "Could not extract update files!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$clean" ]]
|
||||||
|
then
|
||||||
|
echo "Running post-update clean..."
|
||||||
|
cat "_delete.txt" | while read -r line || [[ -n $line ]];
|
||||||
|
do
|
||||||
|
rm -f "$directory/$line"
|
||||||
|
if [[ $? -ne 0 ]]
|
||||||
|
then
|
||||||
|
echo "Could not clean $directory/$line!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Removing temporary files..."
|
||||||
|
rm -f "$fullpath"
|
||||||
|
|
||||||
|
if [[ $? -ne 0 ]]
|
||||||
|
then
|
||||||
|
echo "Could not remove update files!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "$directory/StartIW4MAdmin.sh"
|
||||||
|
chmod +x "$directory/UpdateIW4MAdmin.sh"
|
||||||
|
|
||||||
|
executionTime=$(($SECONDS - start))
|
||||||
|
echo "Update completed successfully in $executionTime seconds!"
|
@ -121,6 +121,7 @@ steps:
|
|||||||
script: |
|
script: |
|
||||||
echo changing to encoding for linux start script
|
echo changing to encoding for linux start script
|
||||||
dos2unix $(outputFolder)\StartIW4MAdmin.sh
|
dos2unix $(outputFolder)\StartIW4MAdmin.sh
|
||||||
|
dos2unix $(outputFolder)\UpdateIW4MAdmin.sh
|
||||||
echo creating website version filename
|
echo creating website version filename
|
||||||
@echo IW4MAdmin-$(Build.BuildNumber) > $(Build.ArtifactStagingDirectory)\version_$(releaseType).txt
|
@echo IW4MAdmin-$(Build.BuildNumber) > $(Build.ArtifactStagingDirectory)\version_$(releaseType).txt
|
||||||
workingDirectory: '$(Build.Repository.LocalPath)\Application\BuildScripts'
|
workingDirectory: '$(Build.Repository.LocalPath)\Application\BuildScripts'
|
||||||
|
@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
DeploymentFiles\PostPublish.ps1 = DeploymentFiles\PostPublish.ps1
|
DeploymentFiles\PostPublish.ps1 = DeploymentFiles\PostPublish.ps1
|
||||||
README.md = README.md
|
README.md = README.md
|
||||||
version.txt = version.txt
|
version.txt = version.txt
|
||||||
|
DeploymentFiles\UpdateIW4MAdmin.ps1 = DeploymentFiles\UpdateIW4MAdmin.ps1
|
||||||
|
DeploymentFiles\UpdateIW4MAdmin.sh = DeploymentFiles\UpdateIW4MAdmin.sh
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedLibraryCore", "SharedLibraryCore\SharedLibraryCore.csproj", "{AA0541A2-8D51-4AD9-B0AC-3D1F5B162481}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedLibraryCore", "SharedLibraryCore\SharedLibraryCore.csproj", "{AA0541A2-8D51-4AD9-B0AC-3D1F5B162481}"
|
||||||
|
@ -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="2022.1.25.2" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.28.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -65,6 +65,7 @@ namespace AutomessageFeed
|
|||||||
|
|
||||||
public async Task OnLoadAsync(IManager manager)
|
public async Task OnLoadAsync(IManager manager)
|
||||||
{
|
{
|
||||||
|
await _configurationHandler.BuildAsync();
|
||||||
if (_configurationHandler.Configuration() == null)
|
if (_configurationHandler.Configuration() == null)
|
||||||
{
|
{
|
||||||
_configurationHandler.Set((Configuration)new Configuration().Generate());
|
_configurationHandler.Set((Configuration)new Configuration().Generate());
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.25.2" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.28.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -1,29 +1,25 @@
|
|||||||
using LiveRadar.Configuration;
|
using LiveRadar.Configuration;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace LiveRadar.Web.Controllers
|
namespace LiveRadar.Web.Controllers
|
||||||
{
|
{
|
||||||
public class RadarController : BaseController
|
public class RadarController : BaseController
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings()
|
|
||||||
{
|
|
||||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
|
||||||
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly IManager _manager;
|
private readonly IManager _manager;
|
||||||
private readonly LiveRadarConfiguration _config;
|
private static LiveRadarConfiguration _config;
|
||||||
|
private readonly IConfigurationHandler<LiveRadarConfiguration> _configurationHandler;
|
||||||
|
|
||||||
public RadarController(IManager manager, IConfigurationHandlerFactory configurationHandlerFactory) : base(manager)
|
public RadarController(IManager manager, IConfigurationHandlerFactory configurationHandlerFactory) : base(manager)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_config = configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration").Configuration() ?? new LiveRadarConfiguration();
|
_configurationHandler =
|
||||||
|
configurationHandlerFactory.GetConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@ -46,7 +42,7 @@ namespace LiveRadar.Web.Controllers
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("Radar/{serverId}/Map")]
|
[Route("Radar/{serverId}/Map")]
|
||||||
public IActionResult Map(long? serverId = null)
|
public async Task<IActionResult> Map(long? serverId = null)
|
||||||
{
|
{
|
||||||
var server = serverId == null ? _manager.GetServers().FirstOrDefault() : _manager.GetServers().FirstOrDefault(_server => _server.EndPoint == serverId);
|
var server = serverId == null ? _manager.GetServers().FirstOrDefault() : _manager.GetServers().FirstOrDefault(_server => _server.EndPoint == serverId);
|
||||||
|
|
||||||
@ -54,6 +50,12 @@ namespace LiveRadar.Web.Controllers
|
|||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
await _configurationHandler.BuildAsync();
|
||||||
|
_config = _configurationHandler.Configuration() ?? new LiveRadarConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
var map = _config.Maps.FirstOrDefault(_map => _map.Name == server.CurrentMap.Name);
|
var map = _config.Maps.FirstOrDefault(_map => _map.Name == server.CurrentMap.Name);
|
||||||
|
|
||||||
@ -93,4 +95,4 @@ namespace LiveRadar.Web.Controllers
|
|||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.25.2" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.28.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -103,6 +103,7 @@ namespace LiveRadar
|
|||||||
|
|
||||||
public async Task OnLoadAsync(IManager manager)
|
public async Task OnLoadAsync(IManager manager)
|
||||||
{
|
{
|
||||||
|
await _configurationHandler.BuildAsync();
|
||||||
if (_configurationHandler.Configuration() == null)
|
if (_configurationHandler.Configuration() == null)
|
||||||
{
|
{
|
||||||
_configurationHandler.Set((LiveRadarConfiguration)new LiveRadarConfiguration().Generate());
|
_configurationHandler.Set((LiveRadarConfiguration)new LiveRadarConfiguration().Generate());
|
||||||
|
@ -3,6 +3,7 @@ using SharedLibraryCore;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
// ReSharper disable CompareOfFloatsByEqualityOperator
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||||||
|
#pragma warning disable CS0659
|
||||||
|
|
||||||
namespace LiveRadar
|
namespace LiveRadar
|
||||||
{
|
{
|
||||||
@ -23,9 +24,7 @@ namespace LiveRadar
|
|||||||
public Vector3 RadianAngles => new Vector3(ViewAngles.X.ToRadians(), ViewAngles.Y.ToRadians(), ViewAngles.Z.ToRadians());
|
public Vector3 RadianAngles => new Vector3(ViewAngles.X.ToRadians(), ViewAngles.Y.ToRadians(), ViewAngles.Z.ToRadians());
|
||||||
public int Id => GetHashCode();
|
public int Id => GetHashCode();
|
||||||
|
|
||||||
#pragma warning disable CS0659
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
#pragma warning restore CS0659
|
|
||||||
{
|
{
|
||||||
if (obj is RadarEvent re)
|
if (obj is RadarEvent re)
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.25.2" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.28.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -76,6 +76,7 @@ namespace IW4MAdmin.Plugins.Login
|
|||||||
{
|
{
|
||||||
AuthorizedClients = new ConcurrentDictionary<int, bool>();
|
AuthorizedClients = new ConcurrentDictionary<int, bool>();
|
||||||
|
|
||||||
|
await _configHandler.BuildAsync();
|
||||||
if (_configHandler.Configuration() == null)
|
if (_configHandler.Configuration() == null)
|
||||||
{
|
{
|
||||||
_configHandler.Set((Configuration)new Configuration().Generate());
|
_configHandler.Set((Configuration)new Configuration().Generate());
|
||||||
|
@ -109,6 +109,7 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
|||||||
|
|
||||||
public async Task OnLoadAsync(IManager manager)
|
public async Task OnLoadAsync(IManager manager)
|
||||||
{
|
{
|
||||||
|
await _configHandler.BuildAsync();
|
||||||
if (_configHandler.Configuration() == null)
|
if (_configHandler.Configuration() == null)
|
||||||
{
|
{
|
||||||
_configHandler.Set((Configuration)new Configuration().Generate());
|
_configHandler.Set((Configuration)new Configuration().Generate());
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.25.2" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.28.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -48,6 +48,7 @@ namespace Stats.Client
|
|||||||
await LoadServers();
|
await LoadServers();
|
||||||
_distributionCache.SetCacheItem((async (set, token) =>
|
_distributionCache.SetCacheItem((async (set, token) =>
|
||||||
{
|
{
|
||||||
|
await _configurationHandler.BuildAsync();
|
||||||
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
||||||
|
|
||||||
var distributions = new Dictionary<long, Extensions.LogParams>();
|
var distributions = new Dictionary<long, Extensions.LogParams>();
|
||||||
@ -73,6 +74,7 @@ namespace Stats.Client
|
|||||||
|
|
||||||
_maxZScoreCache.SetCacheItem(async (set, token) =>
|
_maxZScoreCache.SetCacheItem(async (set, token) =>
|
||||||
{
|
{
|
||||||
|
await _configurationHandler.BuildAsync();
|
||||||
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
||||||
|
|
||||||
var zScore = await set
|
var zScore = await set
|
||||||
|
@ -3,9 +3,7 @@ using Stats.Client.Abstractions;
|
|||||||
using Stats.Client.Game;
|
using Stats.Client.Game;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using IW4MAdmin.Plugins.Stats.Config;
|
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using Stats.Config;
|
using Stats.Config;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
@ -16,10 +14,10 @@ namespace Stats.Client
|
|||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly StatsConfiguration _config;
|
private readonly StatsConfiguration _config;
|
||||||
|
|
||||||
public WeaponNameParser(ILogger<WeaponNameParser> logger, IConfigurationHandler<StatsConfiguration> config)
|
public WeaponNameParser(ILogger<WeaponNameParser> logger, StatsConfiguration config)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_config = config.Configuration();
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WeaponInfo Parse(string weaponName, Server.Game gameName)
|
public WeaponInfo Parse(string weaponName, Server.Game gameName)
|
||||||
@ -67,4 +65,4 @@ namespace Stats.Client
|
|||||||
return weaponInfo;
|
return weaponInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
private readonly ConcurrentDictionary<long, ServerStats> _servers;
|
private readonly ConcurrentDictionary<long, ServerStats> _servers;
|
||||||
private readonly ILogger _log;
|
private readonly ILogger _log;
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
private readonly IConfigurationHandler<StatsConfiguration> _configHandler;
|
private readonly StatsConfiguration _config;
|
||||||
private static List<EFServer> serverModels;
|
private static List<EFServer> serverModels;
|
||||||
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";
|
||||||
@ -47,13 +47,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
private readonly IServerDistributionCalculator _serverDistributionCalculator;
|
private readonly IServerDistributionCalculator _serverDistributionCalculator;
|
||||||
|
|
||||||
public StatManager(ILogger<StatManager> logger, IManager mgr, IDatabaseContextFactory contextFactory,
|
public StatManager(ILogger<StatManager> logger, IManager mgr, IDatabaseContextFactory contextFactory,
|
||||||
IConfigurationHandler<StatsConfiguration> configHandler,
|
StatsConfiguration statsConfig,
|
||||||
IServerDistributionCalculator serverDistributionCalculator)
|
IServerDistributionCalculator serverDistributionCalculator)
|
||||||
{
|
{
|
||||||
_servers = new ConcurrentDictionary<long, ServerStats>();
|
_servers = new ConcurrentDictionary<long, ServerStats>();
|
||||||
_log = logger;
|
_log = logger;
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
_configHandler = configHandler;
|
_config = statsConfig;
|
||||||
_serverDistributionCalculator = serverDistributionCalculator;
|
_serverDistributionCalculator = serverDistributionCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
r.When > fifteenDaysAgo &&
|
r.When > fifteenDaysAgo &&
|
||||||
r.RatingHistory.Client.Level != EFClient.Permission.Banned &&
|
r.RatingHistory.Client.Level != EFClient.Permission.Banned &&
|
||||||
r.Newest &&
|
r.Newest &&
|
||||||
r.ActivityAmount >= _configHandler.Configuration().TopPlayersMinPlayTime;
|
r.ActivityAmount >= _config.TopPlayersMinPlayTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -87,7 +87,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
await using var context = _contextFactory.CreateContext(enableTracking: false);
|
await using var context = _contextFactory.CreateContext(enableTracking: false);
|
||||||
|
|
||||||
if (_configHandler.Configuration().EnableAdvancedMetrics)
|
if (_config.EnableAdvancedMetrics)
|
||||||
{
|
{
|
||||||
var clientRanking = await context.Set<EFClientRankingHistory>()
|
var clientRanking = await context.Set<EFClientRankingHistory>()
|
||||||
.Where(r => r.ClientId == clientId)
|
.Where(r => r.ClientId == clientId)
|
||||||
@ -126,7 +126,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
&& ranking.PerformanceMetric != null
|
&& ranking.PerformanceMetric != null
|
||||||
&& ranking.Newest
|
&& ranking.Newest
|
||||||
&& ranking.Client.TotalConnectionTime >=
|
&& ranking.Client.TotalConnectionTime >=
|
||||||
_configHandler.Configuration().TopPlayersMinPlayTime;
|
_config.TopPlayersMinPlayTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> GetTotalRankedPlayers(long serverId)
|
public async Task<int> GetTotalRankedPlayers(long serverId)
|
||||||
@ -217,7 +217,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
public async Task<List<TopStatsInfo>> GetTopStats(int start, int count, long? serverId = null)
|
public async Task<List<TopStatsInfo>> GetTopStats(int start, int count, long? serverId = null)
|
||||||
{
|
{
|
||||||
if (_configHandler.Configuration().EnableAdvancedMetrics)
|
if (_config.EnableAdvancedMetrics)
|
||||||
{
|
{
|
||||||
return await GetNewTopStats(start, count, serverId);
|
return await GetNewTopStats(start, count, serverId);
|
||||||
}
|
}
|
||||||
@ -570,7 +570,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
clientStats = UpdateStats(clientStats, pl);
|
clientStats = UpdateStats(clientStats, pl);
|
||||||
await SaveClientStats(clientStats);
|
await SaveClientStats(clientStats);
|
||||||
if (_configHandler.Configuration().EnableAdvancedMetrics)
|
if (_config.EnableAdvancedMetrics)
|
||||||
{
|
{
|
||||||
await UpdateHistoricalRanking(pl.ClientId, clientStats, serverId);
|
await UpdateHistoricalRanking(pl.ClientId, clientStats, serverId);
|
||||||
}
|
}
|
||||||
@ -973,7 +973,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
// update their performance
|
// update their performance
|
||||||
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >=
|
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >=
|
||||||
(Utilities.IsDevelopment ? 0.5 : _configHandler.Configuration().EnableAdvancedMetrics ? 5.0 : 2.5))
|
(Utilities.IsDevelopment ? 0.5 : _config.EnableAdvancedMetrics ? 5.0 : 2.5))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -982,7 +982,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
// for stat history update, but one is already processing that invalidates the original
|
// for stat history update, but one is already processing that invalidates the original
|
||||||
await attackerStats.ProcessingHit.WaitAsync(Utilities.DefaultCommandTimeout,
|
await attackerStats.ProcessingHit.WaitAsync(Utilities.DefaultCommandTimeout,
|
||||||
Plugin.ServerManager.CancellationToken);
|
Plugin.ServerManager.CancellationToken);
|
||||||
if (_configHandler.Configuration().EnableAdvancedMetrics)
|
if (_config.EnableAdvancedMetrics)
|
||||||
{
|
{
|
||||||
await UpdateHistoricalRanking(attacker.ClientId, attackerStats, serverId);
|
await UpdateHistoricalRanking(attacker.ClientId, attackerStats, serverId);
|
||||||
}
|
}
|
||||||
@ -1190,7 +1190,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
public async Task UpdateHistoricalRanking(int clientId, EFClientStatistics clientStats, long serverId)
|
public async Task UpdateHistoricalRanking(int clientId, EFClientStatistics clientStats, long serverId)
|
||||||
{
|
{
|
||||||
await using var context = _contextFactory.CreateContext();
|
await using var context = _contextFactory.CreateContext();
|
||||||
var minPlayTime = _configHandler.Configuration().TopPlayersMinPlayTime;
|
var minPlayTime = _config.TopPlayersMinPlayTime;
|
||||||
|
|
||||||
var performances = await context.Set<EFClientStatistics>()
|
var performances = await context.Set<EFClientStatistics>()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
@ -1208,7 +1208,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
var serverRanking = await context.Set<EFClientStatistics>()
|
var serverRanking = await context.Set<EFClientStatistics>()
|
||||||
.Where(stats => stats.ClientId != clientStats.ClientId)
|
.Where(stats => stats.ClientId != clientStats.ClientId)
|
||||||
.Where(AdvancedClientStatsResourceQueryHelper.GetRankingFunc(
|
.Where(AdvancedClientStatsResourceQueryHelper.GetRankingFunc(
|
||||||
_configHandler.Configuration().TopPlayersMinPlayTime, clientStats.ZScore, serverId))
|
_config.TopPlayersMinPlayTime, clientStats.ZScore, serverId))
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
|
|
||||||
var serverRankingSnapshot = new EFClientRankingHistory
|
var serverRankingSnapshot = new EFClientRankingHistory
|
||||||
|
@ -11,7 +11,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Data.Abstractions;
|
using Data.Abstractions;
|
||||||
using Data.Models.Client;
|
|
||||||
using Data.Models.Client.Stats;
|
using Data.Models.Client.Stats;
|
||||||
using Data.Models.Server;
|
using Data.Models.Server;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -172,6 +171,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
|
|
||||||
public async Task OnLoadAsync(IManager manager)
|
public async Task OnLoadAsync(IManager manager)
|
||||||
{
|
{
|
||||||
|
await Config.BuildAsync();
|
||||||
// load custom configuration
|
// load custom configuration
|
||||||
if (Config.Configuration() == null)
|
if (Config.Configuration() == null)
|
||||||
{
|
{
|
||||||
@ -191,10 +191,8 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
async Task<IEnumerable<InformationResponse>> getStats(ClientPaginationRequest request)
|
async Task<IEnumerable<InformationResponse>> getStats(ClientPaginationRequest request)
|
||||||
{
|
{
|
||||||
IList<EFClientStatistics> clientStats;
|
IList<EFClientStatistics> clientStats;
|
||||||
int messageCount = 0;
|
|
||||||
await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false);
|
await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false);
|
||||||
clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync();
|
clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync();
|
||||||
messageCount = await ctx.Set<EFClientMessage>().CountAsync(_message => _message.ClientId == request.ClientId);
|
|
||||||
|
|
||||||
int kills = clientStats.Sum(c => c.Kills);
|
int kills = clientStats.Sum(c => c.Kills);
|
||||||
int deaths = clientStats.Sum(c => c.Deaths);
|
int deaths = clientStats.Sum(c => c.Deaths);
|
||||||
@ -253,14 +251,6 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
Column = 0,
|
Column = 0,
|
||||||
Order = 5,
|
Order = 5,
|
||||||
Type = MetaType.Information
|
Type = MetaType.Information
|
||||||
},
|
|
||||||
new InformationResponse()
|
|
||||||
{
|
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"],
|
|
||||||
Value = messageCount.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
|
||||||
Column = 1,
|
|
||||||
Order = 4,
|
|
||||||
Type = MetaType.Information
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -451,7 +441,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerManager = manager;
|
ServerManager = manager;
|
||||||
Manager = new StatManager(_managerLogger, manager, _databaseContextFactory, Config, _serverDistributionCalculator);
|
Manager = new StatManager(_managerLogger, manager, _databaseContextFactory, Config.Configuration(), _serverDistributionCalculator);
|
||||||
await _serverDistributionCalculator.Initialize();
|
await _serverDistributionCalculator.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.25.2" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.28.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -35,6 +35,7 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
|
|
||||||
public async Task OnLoadAsync(IManager manager)
|
public async Task OnLoadAsync(IManager manager)
|
||||||
{
|
{
|
||||||
|
await _configHandler.BuildAsync();
|
||||||
if (_configHandler.Configuration() == null)
|
if (_configHandler.Configuration() == null)
|
||||||
{
|
{
|
||||||
_configHandler.Set((WelcomeConfiguration) new WelcomeConfiguration().Generate());
|
_configHandler.Set((WelcomeConfiguration) new WelcomeConfiguration().Generate());
|
||||||
@ -94,7 +95,7 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
msg = msg.Replace("{{ClientLocation}}", await GetCountryName(joining.IPAddressString));
|
msg = msg.Replace("{{ClientLocation}}", await GetCountryName(joining.IPAddressString));
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = msg.Replace("{{TimesConnected}}", joining.Connections.Ordinalize());
|
msg = msg.Replace("{{TimesConnected}}", joining.Connections.Ordinalize(Utilities.CurrentLocalization.Culture));
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
@ -110,7 +111,7 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response =
|
var response =
|
||||||
await wc.GetStringAsync(new Uri($"http://extreme-ip-lookup.com/json/{ip}?key=demo"));
|
await wc.GetStringAsync(new Uri($"http://ip-api.com/json/{ip}"));
|
||||||
var responseObj = JObject.Parse(response);
|
var responseObj = JObject.Parse(response);
|
||||||
response = responseObj["country"]?.ToString();
|
response = responseObj["country"]?.ToString();
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.25.2" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2022.1.28.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
11
README.md
11
README.md
@ -35,11 +35,22 @@ Linux
|
|||||||
* You will need to retrieve your login credentials by typing `!rt` ingame
|
* You will need to retrieve your login credentials by typing `!rt` ingame
|
||||||
|
|
||||||
### Updating
|
### Updating
|
||||||
|
**Manually**
|
||||||
1. Download the latest version of **IW4MAdmin**
|
1. Download the latest version of **IW4MAdmin**
|
||||||
2. Extract the newer version of **IW4MAdmin** into pre-existing **IW4MAdmin** folder and overwrite existing files
|
2. Extract the newer version of **IW4MAdmin** into pre-existing **IW4MAdmin** folder and overwrite existing files
|
||||||
|
|
||||||
_Your configuration and database will be saved_
|
_Your configuration and database will be saved_
|
||||||
|
|
||||||
|
**OR**
|
||||||
|
Use the provided `UpdateIW4MAdmin` script to download and install automatically
|
||||||
|
|
||||||
|
| Argument Windows (Linux) | Description |
|
||||||
|
|--------------------------|-----------------------------------------------------------|
|
||||||
|
| -Silent (s) | Do not prompt for any user input |
|
||||||
|
| -Clean (c) | Clean unneeded files listed in `_delete.txt` after update |
|
||||||
|
| -Verified (v) | Only update releases in the verified stream |
|
||||||
|
| -Directory (d) | Directory to install to |
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
Feel free to join the **IW4MAdmin** [Discord](https://discord.gg/ZZFK5p3)
|
Feel free to join the **IW4MAdmin** [Discord](https://discord.gg/ZZFK5p3)
|
||||||
If you come across an issue, bug, or feature request please post an [issue](https://github.com/RaidMax/IW4M-Admin/issues)
|
If you come across an issue, bug, or feature request please post an [issue](https://github.com/RaidMax/IW4M-Admin/issues)
|
||||||
|
@ -381,9 +381,10 @@ namespace SharedLibraryCore.Commands
|
|||||||
public override async Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
// todo: don't do the lookup here
|
// todo: don't do the lookup here
|
||||||
var penalties = await E.Owner.Manager.GetPenaltyService().GetActivePenaltiesAsync(E.Target.AliasLinkId);
|
var penalties = await E.Owner.Manager.GetPenaltyService().GetActivePenaltiesAsync(E.Target.AliasLinkId, E.Target.CurrentAliasId);
|
||||||
if (penalties.Where(p => p.Type == EFPenalty.PenaltyType.Ban || p.Type == EFPenalty.PenaltyType.TempBan)
|
if (penalties
|
||||||
.FirstOrDefault() != null)
|
.FirstOrDefault(p =>
|
||||||
|
p.Type == EFPenalty.PenaltyType.Ban || p.Type == EFPenalty.PenaltyType.TempBan) != null)
|
||||||
{
|
{
|
||||||
switch ((await E.Target.Unban(E.Data, E.Origin)
|
switch ((await E.Target.Unban(E.Data, E.Origin)
|
||||||
.WaitAsync(Utilities.DefaultCommandTimeout, E.Owner.Manager.CancellationToken)).FailReason)
|
.WaitAsync(Utilities.DefaultCommandTimeout, E.Owner.Manager.CancellationToken)).FailReason)
|
||||||
@ -897,7 +898,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
public override async Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
var existingPenalties = await E.Owner.Manager.GetPenaltyService()
|
var existingPenalties = await E.Owner.Manager.GetPenaltyService()
|
||||||
.GetActivePenaltiesAsync(E.Target.AliasLinkId, E.Target.IPAddress);
|
.GetActivePenaltiesAsync(E.Target.AliasLinkId, E.Target.CurrentAliasId, E.Target.IPAddress);
|
||||||
var penalty = existingPenalties.FirstOrDefault(b => b.Type > EFPenalty.PenaltyType.Kick);
|
var penalty = existingPenalties.FirstOrDefault(b => b.Type > EFPenalty.PenaltyType.Kick);
|
||||||
|
|
||||||
if (penalty == null)
|
if (penalty == null)
|
||||||
@ -1247,4 +1248,4 @@ namespace SharedLibraryCore.Commands
|
|||||||
E.Origin.Tell(await GetNextMap(E.Owner, _translationLookup));
|
E.Origin.Tell(await GetNextMap(E.Owner, _translationLookup));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,8 +147,8 @@ namespace SharedLibraryCore.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
_selectedParser = _rconParsers.FirstOrDefault(p => p.Name == parser);
|
_selectedParser = _rconParsers.FirstOrDefault(p => p.Name == parser);
|
||||||
RConParserVersion = _selectedParser?.Version;
|
RConParserVersion = _selectedParser?.Name;
|
||||||
EventParserVersion = _selectedParser?.Version;
|
EventParserVersion = _selectedParser?.Name;
|
||||||
|
|
||||||
if (index <= 0 || _rconParsers[index].CanGenerateLogPath)
|
if (index <= 0 || _rconParsers[index].CanGenerateLogPath)
|
||||||
{
|
{
|
||||||
|
@ -5,4 +5,4 @@
|
|||||||
string Name();
|
string Name();
|
||||||
IBaseConfiguration Generate();
|
IBaseConfiguration Generate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
{
|
{
|
||||||
string FileName { get; }
|
string FileName { get; }
|
||||||
Task Save();
|
Task Save();
|
||||||
void Build();
|
Task BuildAsync();
|
||||||
T Configuration();
|
T Configuration();
|
||||||
void Set(T config);
|
void Set(T config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
namespace SharedLibraryCore.Interfaces
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// defines the capabilities of the configuration handler factory
|
/// defines the capabilities of the configuration handler factory
|
||||||
/// used to generate new instance of configuration handlers
|
/// used to generate new instance of configuration handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IConfigurationHandlerFactory
|
public interface IConfigurationHandlerFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// generates a new configuration handler
|
/// generates a new configuration handler
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">base configuration type</typeparam>
|
/// <typeparam name="T">base configuration type</typeparam>
|
||||||
/// <param name="name">file name of configuration</param>
|
/// <param name="name">file name of configuration</param>
|
||||||
/// <returns>new configuration handler instance</returns>
|
/// <returns>new configuration handler instance</returns>
|
||||||
IConfigurationHandler<T> GetConfigurationHandler<T>(string name) where T : IBaseConfiguration;
|
IConfigurationHandler<T> GetConfigurationHandler<T>(string name) where T : IBaseConfiguration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// generates a new configuration handler and builds the configuration automatically
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">base configuration type</typeparam>
|
||||||
|
/// <param name="name">file name of configuration</param>
|
||||||
|
/// <returns>new configuration handler instance</returns>
|
||||||
|
Task<IConfigurationHandler<T>> GetConfigurationHandlerAsync<T>(string name) where T : IBaseConfiguration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -653,7 +653,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
|
// 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()
|
var activePenalties = await CurrentServer.Manager.GetPenaltyService()
|
||||||
.GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
.GetActivePenaltiesAsync(AliasLinkId, CurrentAliasId, ipAddress);
|
||||||
var banPenalty = activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Ban);
|
var banPenalty = activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Ban);
|
||||||
var tempbanPenalty =
|
var tempbanPenalty =
|
||||||
activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.TempBan);
|
activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.TempBan);
|
||||||
@ -740,4 +740,4 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
return IsBot ? ClientNumber : (int)NetworkId;
|
return IsBot ? ClientNumber : (int)NetworkId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,10 +168,9 @@ namespace SharedLibraryCore.Services
|
|||||||
|
|
||||||
public async Task<EFClient> Get(int entityId)
|
public async Task<EFClient> Get(int entityId)
|
||||||
{
|
{
|
||||||
// todo: this needs to be optimized for large linked accounts
|
|
||||||
await using var context = _contextFactory.CreateContext(false);
|
await using var context = _contextFactory.CreateContext(false);
|
||||||
|
|
||||||
var client = context.Clients
|
var client = await context.Clients
|
||||||
.Select(_client => new EFClient
|
.Select(_client => new EFClient
|
||||||
{
|
{
|
||||||
ClientId = _client.ClientId,
|
ClientId = _client.ClientId,
|
||||||
@ -187,26 +186,28 @@ namespace SharedLibraryCore.Services
|
|||||||
Name = _client.CurrentAlias.Name,
|
Name = _client.CurrentAlias.Name,
|
||||||
IPAddress = _client.CurrentAlias.IPAddress
|
IPAddress = _client.CurrentAlias.IPAddress
|
||||||
},
|
},
|
||||||
TotalConnectionTime = _client.TotalConnectionTime
|
TotalConnectionTime = _client.TotalConnectionTime,
|
||||||
|
AliasLink = new EFAliasLink
|
||||||
|
{
|
||||||
|
AliasLinkId = _client.AliasLinkId,
|
||||||
|
Children = _client.AliasLink.Children
|
||||||
|
},
|
||||||
|
LinkedAccounts = new Dictionary<int, long>()
|
||||||
|
{
|
||||||
|
{_client.ClientId, _client.NetworkId}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.FirstOrDefault(_client => _client.ClientId == entityId);
|
.FirstOrDefaultAsync(_client => _client.ClientId == entityId);
|
||||||
|
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.AliasLink = new EFAliasLink
|
if (!_appConfig.EnableImplicitAccountLinking)
|
||||||
{
|
{
|
||||||
AliasLinkId = client.AliasLinkId,
|
return client;
|
||||||
Children = await context.Aliases
|
}
|
||||||
.Where(_alias => _alias.LinkId == client.AliasLinkId)
|
|
||||||
.Select(_alias => new EFAlias
|
|
||||||
{
|
|
||||||
Name = _alias.Name,
|
|
||||||
IPAddress = _alias.IPAddress
|
|
||||||
}).ToListAsync()
|
|
||||||
};
|
|
||||||
|
|
||||||
var foundClient = new
|
var foundClient = new
|
||||||
{
|
{
|
||||||
@ -220,11 +221,6 @@ namespace SharedLibraryCore.Services
|
|||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (foundClient == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foundClient.Client.LinkedAccounts = new Dictionary<int, long>();
|
foundClient.Client.LinkedAccounts = new Dictionary<int, long>();
|
||||||
// todo: find out the best way to do this
|
// todo: find out the best way to do this
|
||||||
// I'm doing this here because I don't know the best way to have multiple awaits in the query
|
// I'm doing this here because I don't know the best way to have multiple awaits in the query
|
||||||
|
@ -148,7 +148,7 @@ namespace SharedLibraryCore.Services
|
|||||||
return await iqPenalties.Distinct().ToListAsync();
|
return await iqPenalties.Distinct().ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<EFPenalty>> GetActivePenaltiesAsync(int linkId, int? ip = null,
|
public async Task<List<EFPenalty>> GetActivePenaltiesAsync(int linkId, int currentAliasId, int? ip = null,
|
||||||
bool includePunisherName = false)
|
bool includePunisherName = false)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
@ -163,9 +163,6 @@ namespace SharedLibraryCore.Services
|
|||||||
(p.Expires == null || p.Expires > now);
|
(p.Expires == null || p.Expires > now);
|
||||||
|
|
||||||
await using var context = _contextFactory.CreateContext(false);
|
await using var context = _contextFactory.CreateContext(false);
|
||||||
var iqLinkPenalties = context.Penalties
|
|
||||||
.Where(p => p.LinkId == linkId)
|
|
||||||
.Where(filter);
|
|
||||||
|
|
||||||
IQueryable<EFPenalty> iqIpPenalties;
|
IQueryable<EFPenalty> iqIpPenalties;
|
||||||
|
|
||||||
@ -178,22 +175,21 @@ namespace SharedLibraryCore.Services
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var aliasIps = await context.Aliases.Where(alias => alias.LinkId == linkId && alias.IPAddress != null)
|
var usedIps = await context.Aliases.AsNoTracking()
|
||||||
.Select(alias => alias.IPAddress)
|
.Where(alias => (alias.LinkId == linkId || alias.AliasId == currentAliasId) && alias.IPAddress != null)
|
||||||
.ToListAsync();
|
.Select(alias => alias.IPAddress).ToListAsync();
|
||||||
if (ip != null)
|
|
||||||
{
|
|
||||||
aliasIps.Add(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
iqIpPenalties = context.Penalties
|
var aliasedIds = await context.Aliases.AsNoTracking().Where(alias => usedIps.Contains(alias.IPAddress))
|
||||||
.Where(penalty => aliasIps.Contains(penalty.Offender.CurrentAlias.IPAddress))
|
.Select(alias => alias.LinkId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
iqIpPenalties = context.Penalties.AsNoTracking()
|
||||||
|
.Where(penalty => aliasedIds.Contains(penalty.LinkId) || penalty.LinkId == linkId)
|
||||||
.Where(filter);
|
.Where(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
var activePenalties = (await iqLinkPenalties.ToListAsync())
|
var activeIpPenalties = await iqIpPenalties.ToListAsync();
|
||||||
.Union(await iqIpPenalties.ToListAsync())
|
var activePenalties = activeIpPenalties.Distinct();
|
||||||
.Distinct();
|
|
||||||
|
|
||||||
// this is a bit more performant in memory (ordering)
|
// this is a bit more performant in memory (ordering)
|
||||||
return activePenalties.OrderByDescending(p => p.When).ToList();
|
return activePenalties.OrderByDescending(p => p.When).ToList();
|
||||||
@ -221,4 +217,4 @@ namespace SharedLibraryCore.Services
|
|||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
||||||
<Version>2022.01.25.2</Version>
|
<Version>2022.01.28.1</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
<Company>Forever None</Company>
|
<Company>Forever None</Company>
|
||||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||||
<PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>
|
<PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>default</LangVersion>
|
||||||
<PackageTags>IW4MAdmin</PackageTags>
|
<PackageTags>IW4MAdmin</PackageTags>
|
||||||
<RepositoryUrl>https://github.com/RaidMax/IW4M-Admin/</RepositoryUrl>
|
<RepositoryUrl>https://github.com/RaidMax/IW4M-Admin/</RepositoryUrl>
|
||||||
<PackageProjectUrl>https://www.raidmax.org/IW4MAdmin/</PackageProjectUrl>
|
<PackageProjectUrl>https://www.raidmax.org/IW4MAdmin/</PackageProjectUrl>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<Description>Shared Library for IW4MAdmin</Description>
|
<Description>Shared Library for IW4MAdmin</Description>
|
||||||
<PackageVersion>2022.01.25.2</PackageVersion>
|
<PackageVersion>2022.01.28.1</PackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
||||||
|
@ -125,28 +125,6 @@ namespace SharedLibraryCore
|
|||||||
return str.Length > maxLength ? $"{str.Substring(0, maxLength - 3)}..." : str;
|
return str.Length > maxLength ? $"{str.Substring(0, maxLength - 3)}..." : str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// helper method to get the information about an exception and inner exceptions
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ex"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string GetExceptionInfo(this Exception ex)
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
var depth = 0;
|
|
||||||
while (ex != null)
|
|
||||||
{
|
|
||||||
sb.AppendLine($"Exception[{depth}] Name: {ex.GetType().FullName}");
|
|
||||||
sb.AppendLine($"Exception[{depth}] Message: {ex.Message}");
|
|
||||||
sb.AppendLine($"Exception[{depth}] Call Stack: {ex.StackTrace}");
|
|
||||||
sb.AppendLine($"Exception[{depth}] Source: {ex.Source}");
|
|
||||||
depth++;
|
|
||||||
ex = ex.InnerException;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Permission MatchPermission(string str)
|
public static Permission MatchPermission(string str)
|
||||||
{
|
{
|
||||||
var lookingFor = str.ToLower();
|
var lookingFor = str.ToLower();
|
||||||
@ -1190,4 +1168,4 @@ namespace SharedLibraryCore
|
|||||||
return allRules[index];
|
return allRules[index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Data.Models;
|
using Data.Models;
|
||||||
using IW4MAdmin.Plugins.Stats.Config;
|
|
||||||
using Stats.Config;
|
using Stats.Config;
|
||||||
using WebfrontCore.ViewComponents;
|
using WebfrontCore.ViewComponents;
|
||||||
|
|
||||||
@ -19,13 +18,12 @@ namespace WebfrontCore.Controllers
|
|||||||
public class ClientController : BaseController
|
public class ClientController : BaseController
|
||||||
{
|
{
|
||||||
private readonly IMetaService _metaService;
|
private readonly IMetaService _metaService;
|
||||||
private readonly IConfigurationHandler<StatsConfiguration> _configurationHandler;
|
private readonly StatsConfiguration _config;
|
||||||
|
|
||||||
public ClientController(IManager manager, IMetaService metaService,
|
public ClientController(IManager manager, IMetaService metaService, StatsConfiguration config) : base(manager)
|
||||||
IConfigurationHandler<StatsConfiguration> configurationHandler) : base(manager)
|
|
||||||
{
|
{
|
||||||
_metaService = metaService;
|
_metaService = metaService;
|
||||||
_configurationHandler = configurationHandler;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> ProfileAsync(int id, MetaType? metaFilterType)
|
public async Task<IActionResult> ProfileAsync(int id, MetaType? metaFilterType)
|
||||||
@ -37,9 +35,18 @@ namespace WebfrontCore.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var activePenalties = (await Manager.GetPenaltyService().GetActivePenaltiesAsync(client.AliasLinkId, client.IPAddress));
|
var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(client.AliasLinkId, client.CurrentAliasId, client.IPAddress);
|
||||||
|
|
||||||
|
var persistentMetaTask = new[]
|
||||||
|
{
|
||||||
|
_metaService.GetPersistentMeta(EFMeta.ClientTag, client),
|
||||||
|
_metaService.GetPersistentMeta("GravatarEmail", client)
|
||||||
|
};
|
||||||
|
|
||||||
|
var persistentMeta = await Task.WhenAll(persistentMetaTask);
|
||||||
|
var tag = persistentMeta[0];
|
||||||
|
var gravatar = persistentMeta[1];
|
||||||
|
|
||||||
var tag = await _metaService.GetPersistentMeta(EFMeta.ClientTag, client);
|
|
||||||
if (tag?.LinkedMeta != null)
|
if (tag?.LinkedMeta != null)
|
||||||
{
|
{
|
||||||
client.SetAdditionalProperty(EFMeta.ClientTag, tag.LinkedMeta.Value);
|
client.SetAdditionalProperty(EFMeta.ClientTag, tag.LinkedMeta.Value);
|
||||||
@ -56,7 +63,7 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
displayLevel = string.IsNullOrEmpty(client.Tag) ? displayLevel : $"{displayLevel} ({client.Tag})";
|
displayLevel = string.IsNullOrEmpty(client.Tag) ? displayLevel : $"{displayLevel} ({client.Tag})";
|
||||||
|
|
||||||
var clientDto = new PlayerInfo()
|
var clientDto = new PlayerInfo
|
||||||
{
|
{
|
||||||
Name = client.Name,
|
Name = client.Name,
|
||||||
Level = displayLevel,
|
Level = displayLevel,
|
||||||
@ -93,7 +100,6 @@ namespace WebfrontCore.Controllers
|
|||||||
Before = DateTime.UtcNow
|
Before = DateTime.UtcNow
|
||||||
}, MetaType.Information);
|
}, MetaType.Information);
|
||||||
|
|
||||||
var gravatar = await _metaService.GetPersistentMeta("GravatarEmail", client);
|
|
||||||
if (gravatar != null)
|
if (gravatar != null)
|
||||||
{
|
{
|
||||||
clientDto.Meta.Add(new InformationResponse()
|
clientDto.Meta.Add(new InformationResponse()
|
||||||
@ -107,14 +113,14 @@ namespace WebfrontCore.Controllers
|
|||||||
clientDto.ActivePenalty = activePenalties.OrderByDescending(_penalty => _penalty.Type).FirstOrDefault();
|
clientDto.ActivePenalty = activePenalties.OrderByDescending(_penalty => _penalty.Type).FirstOrDefault();
|
||||||
clientDto.Meta.AddRange(Authorized ? meta : meta.Where(m => !m.IsSensitive));
|
clientDto.Meta.AddRange(Authorized ? meta : meta.Where(m => !m.IsSensitive));
|
||||||
|
|
||||||
string strippedName = clientDto.Name.StripColors();
|
var strippedName = clientDto.Name.StripColors();
|
||||||
ViewBag.Title = strippedName.Substring(strippedName.Length - 1).ToLower()[0] == 's' ?
|
ViewBag.Title = strippedName.Substring(strippedName.Length - 1).ToLower()[0] == 's' ?
|
||||||
strippedName + "'" :
|
strippedName + "'" :
|
||||||
strippedName + "'s";
|
strippedName + "'s";
|
||||||
ViewBag.Title += " " + Localization["WEBFRONT_CLIENT_PROFILE_TITLE"];
|
ViewBag.Title += " " + Localization["WEBFRONT_CLIENT_PROFILE_TITLE"];
|
||||||
ViewBag.Description = $"Client information for {strippedName}";
|
ViewBag.Description = $"Client information for {strippedName}";
|
||||||
ViewBag.Keywords = $"IW4MAdmin, client, profile, {strippedName}";
|
ViewBag.Keywords = $"IW4MAdmin, client, profile, {strippedName}";
|
||||||
ViewBag.UseNewStats = _configurationHandler.Configuration()?.EnableAdvancedMetrics ?? true;
|
ViewBag.UseNewStats = _config?.EnableAdvancedMetrics ?? true;
|
||||||
|
|
||||||
return View("Profile/Index", clientDto);
|
return View("Profile/Index", clientDto);
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
public ClientStatisticsController(IManager manager,
|
public ClientStatisticsController(IManager manager,
|
||||||
IResourceQueryHelper<StatsInfoRequest, AdvancedStatsInfo> queryHelper,
|
IResourceQueryHelper<StatsInfoRequest, AdvancedStatsInfo> queryHelper,
|
||||||
IConfigurationHandler<DefaultSettings> configurationHandler) : base(manager)
|
DefaultSettings defaultConfig) : base(manager)
|
||||||
{
|
{
|
||||||
_queryHelper = queryHelper;
|
_queryHelper = queryHelper;
|
||||||
_defaultConfig = configurationHandler.Configuration();
|
_defaultConfig = defaultConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id:int}/advanced")]
|
[HttpGet("{id:int}/advanced")]
|
||||||
@ -35,4 +35,4 @@ namespace WebfrontCore.Controllers
|
|||||||
return View("~/Views/Client/Statistics/Advanced.cshtml", hitInfo.Results.First());
|
return View("~/Views/Client/Statistics/Advanced.cshtml", hitInfo.Results.First());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,19 +27,18 @@ 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;
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
private readonly IConfigurationHandler<StatsConfiguration> _configurationHandler;
|
private readonly StatsConfiguration _config;
|
||||||
|
|
||||||
public StatsController(ILogger<StatsController> logger, IManager manager, IResourceQueryHelper<ChatSearchQuery,
|
public StatsController(ILogger<StatsController> logger, IManager manager, IResourceQueryHelper<ChatSearchQuery,
|
||||||
MessageResponse> resourceQueryHelper, ITranslationLookup translationLookup,
|
MessageResponse> resourceQueryHelper, ITranslationLookup translationLookup,
|
||||||
IDatabaseContextFactory contextFactory,
|
IDatabaseContextFactory contextFactory, StatsConfiguration config) : base(manager)
|
||||||
IConfigurationHandler<StatsConfiguration> configurationHandler) : base(manager)
|
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_chatResourceQueryHelper = resourceQueryHelper;
|
_chatResourceQueryHelper = resourceQueryHelper;
|
||||||
_translationLookup = translationLookup;
|
_translationLookup = translationLookup;
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
_configurationHandler = configurationHandler;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@ -70,7 +69,7 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
|||||||
serverId = StatManager.GetIdForServer(server);
|
serverId = StatManager.GetIdForServer(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
var results = _configurationHandler.Configuration().EnableAdvancedMetrics
|
var results = _config?.EnableAdvancedMetrics ?? true
|
||||||
? await Plugin.Manager.GetNewTopStats(offset, count, serverId)
|
? await Plugin.Manager.GetNewTopStats(offset, count, serverId)
|
||||||
: await Plugin.Manager.GetTopStats(offset, count, serverId);
|
: await Plugin.Manager.GetTopStats(offset, count, serverId);
|
||||||
|
|
||||||
@ -80,7 +79,7 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
|
|||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewBag.UseNewStats = _configurationHandler.Configuration().EnableAdvancedMetrics;
|
ViewBag.UseNewStats = _config?.EnableAdvancedMetrics;
|
||||||
return View("~/Views/Client/Statistics/Components/TopPlayers/_List.cshtml", results);
|
return View("~/Views/Client/Statistics/Components/TopPlayers/_List.cshtml", results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ namespace WebfrontCore
|
|||||||
services.AddSingleton(Program.ApplicationServiceProvider
|
services.AddSingleton(Program.ApplicationServiceProvider
|
||||||
.GetRequiredService<IConfigurationHandler<DefaultSettings>>());
|
.GetRequiredService<IConfigurationHandler<DefaultSettings>>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider
|
services.AddSingleton(Program.ApplicationServiceProvider
|
||||||
.GetRequiredService<IConfigurationHandler<StatsConfiguration>>());
|
.GetRequiredService<StatsConfiguration>());
|
||||||
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IServerDataViewer>());
|
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IServerDataViewer>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,18 +3,17 @@ using System.Threading.Tasks;
|
|||||||
using IW4MAdmin.Plugins.Stats;
|
using IW4MAdmin.Plugins.Stats;
|
||||||
using IW4MAdmin.Plugins.Stats.Helpers;
|
using IW4MAdmin.Plugins.Stats.Helpers;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using Stats.Config;
|
using Stats.Config;
|
||||||
|
|
||||||
namespace WebfrontCore.ViewComponents
|
namespace WebfrontCore.ViewComponents
|
||||||
{
|
{
|
||||||
public class TopPlayersViewComponent : ViewComponent
|
public class TopPlayersViewComponent : ViewComponent
|
||||||
{
|
{
|
||||||
private readonly IConfigurationHandler<StatsConfiguration> _configurationHandler;
|
private readonly StatsConfiguration _config;
|
||||||
|
|
||||||
public TopPlayersViewComponent(IConfigurationHandler<StatsConfiguration> configurationHandler)
|
public TopPlayersViewComponent(StatsConfiguration config)
|
||||||
{
|
{
|
||||||
_configurationHandler = configurationHandler;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IViewComponentResult> InvokeAsync(int count, int offset, long? serverId = null)
|
public async Task<IViewComponentResult> InvokeAsync(int count, int offset, long? serverId = null)
|
||||||
@ -32,7 +31,7 @@ namespace WebfrontCore.ViewComponents
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ViewBag.UseNewStats = _configurationHandler.Configuration()?.EnableAdvancedMetrics ?? true;
|
ViewBag.UseNewStats = _config?.EnableAdvancedMetrics ?? true;
|
||||||
return View("~/Views/Client/Statistics/Components/TopPlayers/_List.cshtml",
|
return View("~/Views/Client/Statistics/Components/TopPlayers/_List.cshtml",
|
||||||
ViewBag.UseNewStats
|
ViewBag.UseNewStats
|
||||||
? await Plugin.Manager.GetNewTopStats(offset, count, serverId)
|
? await Plugin.Manager.GetNewTopStats(offset, count, serverId)
|
||||||
|
@ -96,37 +96,31 @@
|
|||||||
$('.ip-locate-link').click(function (e) {
|
$('.ip-locate-link').click(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const ip = $(this).data("ip");
|
const ip = $(this).data("ip");
|
||||||
$.getJSON('https://extreme-ip-lookup.com/json/' + ip + '?key=demo')
|
$.getJSON(`https://ipwhois.app/json/${ip}`)
|
||||||
.done(function (response) {
|
.done(function (response) {
|
||||||
$('#mainModal .modal-title').text(ip);
|
$('#mainModal .modal-title').text(ip);
|
||||||
$('#mainModal .modal-body').text('');
|
$('#mainModal .modal-body').text('');
|
||||||
if (response.ipName.length > 0) {
|
|
||||||
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_HOSTNAME']} — ${response.ipName}<br/>`);
|
|
||||||
}
|
|
||||||
if (response.isp.length > 0) {
|
if (response.isp.length > 0) {
|
||||||
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_ISP']} — ${response.isp}<br/>`);
|
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_ISP']} — ${response.isp}<br/>`);
|
||||||
}
|
}
|
||||||
if (response.org.length > 0) {
|
if (response.org.length > 0) {
|
||||||
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_ORG']} — ${response.org}<br/>`);
|
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_ORG']} — ${response.org}<br/>`);
|
||||||
}
|
}
|
||||||
if (response['businessName'].length > 0) {
|
if (response.region.length > 0 || response.city.length > 0 || response.country.length > 0 || response.timezone_gmt.length > 0) {
|
||||||
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_BUSINESS']} — ${response.businessName}<br/>`);
|
|
||||||
}
|
|
||||||
if (response['businessWebsite'].length > 0) {
|
|
||||||
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_WEBSITE']} — ${response.businessWebsite}<br/>`);
|
|
||||||
}
|
|
||||||
if (response.city.length > 0 || response.region.length > 0 || response.country.length > 0) {
|
|
||||||
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_LOCATION']} — `);
|
$('#mainModal .modal-body').append(`${_localization['WEBFRONT_PROFILE_LOOKUP_LOCATION']} — `);
|
||||||
}
|
}
|
||||||
if (response.city.length > 0) {
|
if (response.city.length > 0) {
|
||||||
$('#mainModal .modal-body').append(response.city);
|
$('#mainModal .modal-body').append(response.city);
|
||||||
}
|
}
|
||||||
if (response.region.length > 0) {
|
if (response.region.length > 0) {
|
||||||
$('#mainModal .modal-body').append((response.city.length > 0 ? ', ' : '') + response.region);
|
$('#mainModal .modal-body').append((response.region.length > 0 ? ', ' : '') + response.region);
|
||||||
}
|
}
|
||||||
if (response.country.length > 0) {
|
if (response.country.length > 0) {
|
||||||
$('#mainModal .modal-body').append((response.country.length > 0 ? ', ' : '') + response.country);
|
$('#mainModal .modal-body').append((response.country.length > 0 ? ', ' : '') + response.country);
|
||||||
}
|
}
|
||||||
|
if (response.timezone_gmt.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append((response.timezone_gmt.length > 0 ? ', ' : '') + response.timezone_gmt);
|
||||||
|
}
|
||||||
|
|
||||||
$('#mainModal').modal();
|
$('#mainModal').modal();
|
||||||
})
|
})
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
|
if ($('.scoreboard-container').length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
$(window.location.hash).tab('show');
|
$(window.location.hash).tab('show');
|
||||||
$(`${window.location.hash}_nav`).addClass('active');
|
$(`${window.location.hash}_nav`).addClass('active');
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user