merge to pre (#172)
* update GenerateGuidFromString to resolve to a stable hash code. fix bots not showing up on live radar * add 0.0.0.0 as internal "ip" even though it's not actually a valid IP but for cod4x * implement pm admins command for issue #170 * implement service resolver for script plugins
This commit is contained in:
parent
ad6b6a6465
commit
9117440566
@ -67,13 +67,14 @@ namespace IW4MAdmin.Application
|
|||||||
private readonly IEventHandler _eventHandler;
|
private readonly IEventHandler _eventHandler;
|
||||||
private readonly IScriptCommandFactory _scriptCommandFactory;
|
private readonly IScriptCommandFactory _scriptCommandFactory;
|
||||||
private readonly IMetaRegistration _metaRegistration;
|
private readonly IMetaRegistration _metaRegistration;
|
||||||
|
private readonly IScriptPluginServiceResolver _scriptPluginServiceResolver;
|
||||||
|
|
||||||
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
||||||
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
||||||
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
||||||
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
||||||
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, IMetaService metaService,
|
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory, IMetaService metaService,
|
||||||
IMetaRegistration metaRegistration)
|
IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver)
|
||||||
{
|
{
|
||||||
MiddlewareActionHandler = actionHandler;
|
MiddlewareActionHandler = actionHandler;
|
||||||
_servers = new ConcurrentBag<Server>();
|
_servers = new ConcurrentBag<Server>();
|
||||||
@ -100,6 +101,7 @@ namespace IW4MAdmin.Application
|
|||||||
_eventHandler = eventHandler;
|
_eventHandler = eventHandler;
|
||||||
_scriptCommandFactory = scriptCommandFactory;
|
_scriptCommandFactory = scriptCommandFactory;
|
||||||
_metaRegistration = metaRegistration;
|
_metaRegistration = metaRegistration;
|
||||||
|
_scriptPluginServiceResolver = scriptPluginServiceResolver;
|
||||||
Plugins = plugins;
|
Plugins = plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,12 +279,12 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
if (plugin is ScriptPlugin scriptPlugin)
|
if (plugin is ScriptPlugin scriptPlugin)
|
||||||
{
|
{
|
||||||
await scriptPlugin.Initialize(this, _scriptCommandFactory);
|
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver);
|
||||||
scriptPlugin.Watcher.Changed += async (sender, e) =>
|
scriptPlugin.Watcher.Changed += async (sender, e) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await scriptPlugin.Initialize(this, _scriptCommandFactory);
|
await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -449,7 +451,8 @@ namespace IW4MAdmin.Application
|
|||||||
Name = cmd.Name,
|
Name = cmd.Name,
|
||||||
Alias = cmd.Alias,
|
Alias = cmd.Alias,
|
||||||
MinimumPermission = cmd.Permission,
|
MinimumPermission = cmd.Permission,
|
||||||
AllowImpersonation = cmd.AllowImpersonation
|
AllowImpersonation = cmd.AllowImpersonation,
|
||||||
|
SupportedGames = cmd.SupportedGames
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,6 +249,7 @@ namespace IW4MAdmin.Application
|
|||||||
.AddSingleton<IEntityService<EFClient>, ClientService>()
|
.AddSingleton<IEntityService<EFClient>, ClientService>()
|
||||||
.AddSingleton<IMetaService, MetaService>()
|
.AddSingleton<IMetaService, MetaService>()
|
||||||
.AddSingleton<IMetaRegistration, MetaRegistration>()
|
.AddSingleton<IMetaRegistration, MetaRegistration>()
|
||||||
|
.AddSingleton<IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
|
||||||
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
|
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
|
||||||
|
@ -61,7 +61,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
_onProcessing.Dispose();
|
_onProcessing.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Initialize(IManager manager, IScriptCommandFactory scriptCommandFactory)
|
public async Task Initialize(IManager manager, IScriptCommandFactory scriptCommandFactory, IScriptPluginServiceResolver serviceResolver)
|
||||||
{
|
{
|
||||||
await _onProcessing.WaitAsync();
|
await _onProcessing.WaitAsync();
|
||||||
|
|
||||||
@ -114,6 +114,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
|
|
||||||
_scriptEngine.Execute(script);
|
_scriptEngine.Execute(script);
|
||||||
_scriptEngine.SetValue("_localization", Utilities.CurrentLocalization);
|
_scriptEngine.SetValue("_localization", Utilities.CurrentLocalization);
|
||||||
|
_scriptEngine.SetValue("_serviceResolver", serviceResolver);
|
||||||
dynamic pluginObject = _scriptEngine.GetValue("plugin").ToObject();
|
dynamic pluginObject = _scriptEngine.GetValue("plugin").ToObject();
|
||||||
|
|
||||||
Author = pluginObject.author;
|
Author = pluginObject.author;
|
||||||
@ -164,6 +165,11 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
successfullyLoaded = true;
|
successfullyLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
catch (JavaScriptException ex)
|
||||||
|
{
|
||||||
|
throw new PluginException($"An error occured while initializing script plugin: {ex.Error} (Line: {ex.Location.Start.Line}, Character: {ex.Location.Start.Column})") { PluginFile = _fileName };
|
||||||
|
}
|
||||||
|
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
|
31
Application/Misc/ScriptPluginServiceResolver.cs
Normal file
31
Application/Misc/ScriptPluginServiceResolver.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// implementation of IScriptPluginServiceResolver
|
||||||
|
/// </summary>
|
||||||
|
public class ScriptPluginServiceResolver : IScriptPluginServiceResolver
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public ScriptPluginServiceResolver(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ResolveService(string serviceName)
|
||||||
|
{
|
||||||
|
var serviceType = typeof(IScriptPluginServiceResolver).Assembly.GetTypes().FirstOrDefault(_type => _type.Name == serviceName);
|
||||||
|
|
||||||
|
if (serviceType == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"No service type '{serviceName}' defined in IW4MAdmin assembly");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _serviceProvider.GetService(serviceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -44,6 +44,8 @@ let plugin = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoadAsync: function (manager) {
|
onLoadAsync: function (manager) {
|
||||||
|
this.logger = _serviceResolver.ResolveService("ILogger");
|
||||||
|
this.logger.WriteDebug("sample plugin loaded");
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnloadAsync: function () {
|
onUnloadAsync: function () {
|
||||||
|
@ -5,6 +5,7 @@ using SharedLibraryCore.Commands;
|
|||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore
|
namespace SharedLibraryCore
|
||||||
{
|
{
|
||||||
@ -13,7 +14,7 @@ namespace SharedLibraryCore
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Command : IManagerCommand
|
public abstract class Command : IManagerCommand
|
||||||
{
|
{
|
||||||
private readonly CommandConfiguration _config;
|
protected readonly CommandConfiguration _config;
|
||||||
protected readonly ITranslationLookup _translationLookup;
|
protected readonly ITranslationLookup _translationLookup;
|
||||||
protected ILogger logger;
|
protected ILogger logger;
|
||||||
|
|
||||||
@ -113,6 +114,25 @@ namespace SharedLibraryCore
|
|||||||
}
|
}
|
||||||
private EFClient.Permission permission;
|
private EFClient.Permission permission;
|
||||||
|
|
||||||
|
public Game[] SupportedGames
|
||||||
|
{
|
||||||
|
get => supportedGames;
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var savedGames = _config?.Commands[GetType().Name].SupportedGames;
|
||||||
|
supportedGames = savedGames?.Length != 0 ? savedGames : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
supportedGames = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Game[] supportedGames;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Argument list for the command
|
/// Argument list for the command
|
||||||
|
37
SharedLibraryCore/Commands/PrivateMessageAdminsCommand.cs
Normal file
37
SharedLibraryCore/Commands/PrivateMessageAdminsCommand.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using SharedLibraryCore.Configuration;
|
||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Commands
|
||||||
|
{
|
||||||
|
public class PrivateMessageAdminsCommand : Command
|
||||||
|
{
|
||||||
|
public PrivateMessageAdminsCommand(CommandConfiguration config, ITranslationLookup lookup) : base(config, lookup)
|
||||||
|
{
|
||||||
|
Name = "privatemessageadmin";
|
||||||
|
Description = lookup["COMMANDS_PMADMINS_DESC"];
|
||||||
|
Alias = "pma";
|
||||||
|
Permission = EFClient.Permission.Moderator;
|
||||||
|
SupportedGames = new[] { Game.IW4, Game.IW5 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task ExecuteAsync(GameEvent E)
|
||||||
|
{
|
||||||
|
bool isGameSupported = _config.Commands[nameof(PrivateMessageAdminsCommand)].SupportedGames.Length > 0 &&
|
||||||
|
_config.Commands[nameof(PrivateMessageAdminsCommand)].SupportedGames.Contains(E.Owner.GameName);
|
||||||
|
|
||||||
|
if (!isGameSupported)
|
||||||
|
{
|
||||||
|
E.Origin.Tell(_translationLookup["COMMANDS_GAME_NOT_SUPPORTED"].FormatExt(nameof(PrivateMessageAdminsCommand)));
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
E.Owner.ToAdmins(E.Data);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json;
|
||||||
using System.Text.Json.Serialization;
|
using Newtonsoft.Json.Converters;
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Configuration
|
namespace SharedLibraryCore.Configuration
|
||||||
{
|
{
|
||||||
@ -29,5 +30,11 @@ namespace SharedLibraryCore.Configuration
|
|||||||
/// Indicates if the command can be run by another user (impersonation)
|
/// Indicates if the command can be run by another user (impersonation)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowImpersonation { get; set; }
|
public bool AllowImpersonation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the games supporting the functionality of the command
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
|
||||||
|
public Game[] SupportedGames { get; set; } = new Game[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
@ -35,6 +36,11 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Permission Permission { get; }
|
Permission Permission { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Games the command is supported on
|
||||||
|
/// </summary>
|
||||||
|
Game[] SupportedGames { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Syntax for using the command
|
/// Syntax for using the command
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
10
SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs
Normal file
10
SharedLibraryCore/Interfaces/IScriptPluginServiceResolver.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// interface used to dynamically resolve services by string name
|
||||||
|
/// </summary>
|
||||||
|
public interface IScriptPluginServiceResolver
|
||||||
|
{
|
||||||
|
object ResolveService(string serviceName);
|
||||||
|
}
|
||||||
|
}
|
@ -537,5 +537,46 @@ namespace ApplicationTests
|
|||||||
Assert.IsTrue(result.IsBroadcast);
|
Assert.IsTrue(result.IsBroadcast);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region PMADMINS
|
||||||
|
[Test]
|
||||||
|
public async Task Test_PrivateMessageAdmins_HappyPath()
|
||||||
|
{
|
||||||
|
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
|
||||||
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
|
var origin = ClientGenerators.CreateDatabaseClient();
|
||||||
|
origin.Level = Permission.Administrator;
|
||||||
|
origin.CurrentServer = server;
|
||||||
|
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, "", server);
|
||||||
|
cmdConfig.Commands.Add(nameof(PrivateMessageAdminsCommand), new CommandProperties { SupportedGames = new[] { server.GameName } });
|
||||||
|
|
||||||
|
server.Clients[0] = origin;
|
||||||
|
server.Clients[1] = origin;
|
||||||
|
await cmd.ExecuteAsync(gameEvent);
|
||||||
|
int expectedEvents = 2;
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedEvents, mockEventHandler.Events.Count(_event => _event.Type == GameEvent.EventType.Tell));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Test_PrivateMessageAdmins_GameNotSupported()
|
||||||
|
{
|
||||||
|
var cmd = new PrivateMessageAdminsCommand(cmdConfig, transLookup);
|
||||||
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
|
var origin = ClientGenerators.CreateDatabaseClient();
|
||||||
|
origin.Level = Permission.Administrator;
|
||||||
|
origin.CurrentServer = server;
|
||||||
|
var gameEvent = EventGenerators.GenerateEvent(GameEvent.EventType.Command, "", server);
|
||||||
|
gameEvent.Origin = origin;
|
||||||
|
cmdConfig.Commands.Add(nameof(PrivateMessageAdminsCommand), new CommandProperties());
|
||||||
|
|
||||||
|
server.Clients[0] = origin;
|
||||||
|
server.Clients[1] = origin;
|
||||||
|
await cmd.ExecuteAsync(gameEvent);
|
||||||
|
int expectedEvents = 1;
|
||||||
|
|
||||||
|
Assert.AreEqual(expectedEvents, mockEventHandler.Events.Count(_event => _event.Type == GameEvent.EventType.Tell));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user