add ServerCommandRequestExecuteEvent implementation

This commit is contained in:
RaidMax 2023-04-09 14:07:30 -05:00
parent c550d424dd
commit 22af762a9d
8 changed files with 109 additions and 42 deletions

View File

@ -309,6 +309,7 @@ namespace IW4MAdmin.Application
#region EVENTS
IGameServerEventSubscriptions.ServerValueRequested += OnServerValueRequested;
IGameServerEventSubscriptions.ServerValueSetRequested += OnServerValueSetRequested;
IGameServerEventSubscriptions.ServerCommandExecuteRequested += OnServerCommandExecuteRequested;
await IManagementEventSubscriptions.InvokeLoadAsync(this, CancellationToken);
# endregion
@ -788,9 +789,63 @@ namespace IW4MAdmin.Application
}
}
private async Task OnServerValueSetRequested(ServerValueSetRequestEvent requestEvent, CancellationToken token)
private Task OnServerValueSetRequested(ServerValueSetRequestEvent requestEvent, CancellationToken token)
{
if (requestEvent.Server is not IW4MServer server)
return ExecuteWrapperForServerQuery(requestEvent, token, async (innerEvent) =>
{
if (innerEvent.DelayMs.HasValue)
{
await Task.Delay(innerEvent.DelayMs.Value, token);
}
if (innerEvent.TimeoutMs is not null)
{
using var timeoutTokenSource = new CancellationTokenSource(innerEvent.TimeoutMs.Value);
using var linkedTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, token);
token = linkedTokenSource.Token;
}
await innerEvent.Server.SetDvarAsync(innerEvent.ValueName, innerEvent.Value, token);
}, (completed, innerEvent) =>
{
QueueEvent(new ServerValueSetCompleteEvent
{
Server = innerEvent.Server,
Source = innerEvent.Server,
Success = completed,
Value = innerEvent.Value,
ValueName = innerEvent.ValueName
});
return Task.CompletedTask;
});
}
private Task OnServerCommandExecuteRequested(ServerCommandRequestExecuteEvent executeEvent, CancellationToken token)
{
return ExecuteWrapperForServerQuery(executeEvent, token, async (innerEvent) =>
{
if (innerEvent.DelayMs.HasValue)
{
await Task.Delay(innerEvent.DelayMs.Value, token);
}
if (innerEvent.TimeoutMs is not null)
{
using var timeoutTokenSource = new CancellationTokenSource(innerEvent.TimeoutMs.Value);
using var linkedTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, token);
token = linkedTokenSource.Token;
}
await innerEvent.Server.ExecuteCommandAsync(innerEvent.Command, token);
}, (_, __) => Task.CompletedTask);
}
private async Task ExecuteWrapperForServerQuery<TEventType>(TEventType serverEvent, CancellationToken token,
Func<TEventType, Task> action, Func<bool, TEventType, Task> complete) where TEventType : GameServerEvent
{
if (serverEvent.Server is not IW4MServer)
{
return;
}
@ -798,20 +853,7 @@ namespace IW4MAdmin.Application
var completed = false;
try
{
if (requestEvent.DelayMs.HasValue)
{
await Task.Delay(requestEvent.DelayMs.Value, token);
}
if (requestEvent.TimeoutMs is not null)
{
using var timeoutTokenSource = new CancellationTokenSource(requestEvent.TimeoutMs.Value);
using var linkedTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(timeoutTokenSource.Token, token);
token = linkedTokenSource.Token;
}
await server.SetDvarAsync(requestEvent.ValueName, requestEvent.Value, token);
await action(serverEvent);
completed = true;
}
catch
@ -820,14 +862,7 @@ namespace IW4MAdmin.Application
}
finally
{
QueueEvent(new ServerValueSetCompleteEvent
{
Server = server,
Source = server,
Success = completed,
Value = requestEvent.Value,
ValueName = requestEvent.ValueName
});
await complete(completed, serverEvent);
}
}

View File

@ -1606,6 +1606,12 @@ namespace IW4MAdmin
});
}
public override Task<string[]> ExecuteCommandAsync(string command, CancellationToken token = default) =>
Utilities.ExecuteCommandAsync(this, command, token);
public override Task SetDvarAsync(string name, object value, CancellationToken token = default) =>
Utilities.SetDvarAsync(this, name, value, token);
public override async Task TempBan(string reason, TimeSpan length, EFClient targetClient, EFClient originClient)
{
// ensure player gets kicked if command not performed on them in the same server

View File

@ -1,8 +0,0 @@
using System;
namespace SharedLibraryCore.Events.Management;
public class NotifyAfterDelayCompleteEvent : ManagementEvent
{
public Delegate Action { get; init; }
}

View File

@ -1,9 +0,0 @@
using System;
namespace SharedLibraryCore.Events.Management;
public class NotifyAfterDelayRequestEvent : ManagementEvent
{
public int DelayMs { get; init; }
public Action Action { get; init; }
}

View File

@ -0,0 +1,16 @@
using SharedLibraryCore.Interfaces;
namespace SharedLibraryCore.Events.Server;
public class ServerCommandRequestExecuteEvent : GameServerEvent
{
public ServerCommandRequestExecuteEvent(string command, IGameServer server)
{
Command = command;
Server = server;
}
public string Command { get; init; }
public int? DelayMs { get; init; }
public int? TimeoutMs { get; init; }
}

View File

@ -38,6 +38,11 @@ public interface IGameServerEventSubscriptions
/// </summary>
static event Func<ClientDataUpdateEvent, CancellationToken, Task> ClientDataUpdated;
/// <summary>
/// Raised when a command is requested to be executed on a game server
/// </summary>
static event Func<ServerCommandRequestExecuteEvent, CancellationToken, Task> ServerCommandExecuteRequested;
/// <summary>
/// Raised when a command was executed on a game server
/// <value><see cref="ServerCommandExecuteEvent"/></value>
@ -67,7 +72,7 @@ public interface IGameServerEventSubscriptions
/// <value><see cref="ServerValueSetRequestEvent"/></value>
/// </summary>
static event Func<ServerValueSetCompleteEvent, CancellationToken, Task> ServerValueSetCompleted;
static Task InvokeEventAsync(CoreEvent coreEvent, CancellationToken token)
{
return coreEvent switch
@ -77,6 +82,7 @@ public interface IGameServerEventSubscriptions
ConnectionInterruptEvent connectionInterruptEvent => ConnectionInterrupted?.InvokeAsync(connectionInterruptEvent, token) ?? Task.CompletedTask,
ConnectionRestoreEvent connectionRestoreEvent => ConnectionRestored?.InvokeAsync(connectionRestoreEvent, token) ?? Task.CompletedTask,
ClientDataUpdateEvent clientDataUpdateEvent => ClientDataUpdated?.InvokeAsync(clientDataUpdateEvent, token) ?? Task.CompletedTask,
ServerCommandRequestExecuteEvent serverCommandRequestExecuteEvent => ServerCommandExecuteRequested?.InvokeAsync(serverCommandRequestExecuteEvent, token) ?? Task.CompletedTask,
ServerCommandExecuteEvent dataReceiveEvent => ServerCommandExecuted?.InvokeAsync(dataReceiveEvent, token) ?? Task.CompletedTask,
ServerValueRequestEvent serverValueRequestEvent => ServerValueRequested?.InvokeAsync(serverValueRequestEvent, token) ?? Task.CompletedTask,
ServerValueReceiveEvent serverValueReceiveEvent => ServerValueReceived?.InvokeAsync(serverValueReceiveEvent, token) ?? Task.CompletedTask,
@ -93,6 +99,7 @@ public interface IGameServerEventSubscriptions
ConnectionInterrupted = null;
ConnectionRestored = null;
ClientDataUpdated = null;
ServerCommandExecuteRequested = null;
ServerCommandExecuted = null;
ServerValueReceived = null;
ServerValueRequested = null;

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Data.Models;
using SharedLibraryCore.Database.Models;
@ -17,6 +18,23 @@ namespace SharedLibraryCore.Interfaces
/// <param name="previousPenalty">previous penalty the kick is occuring for (if applicable)</param>
/// <returns></returns>
Task Kick(string reason, EFClient target, EFClient origin, EFPenalty previousPenalty = null);
/// <summary>
/// Execute a server command
/// </summary>
/// <param name="command">Server command to execute</param>
/// <param name="token"><see cref="CancellationToken"/></param>
/// <returns>Collection of console command output lines</returns>
Task<string[]> ExecuteCommandAsync(string command, CancellationToken token = default);
/// <summary>
/// Set value for server dvar
/// </summary>
/// <param name="name">Name of the server value to set</param>
/// <param name="value">Value of the server value</param>
/// <param name="token"><see cref="CancellationToken"/></param>
/// <returns></returns>
Task SetDvarAsync(string name, object value, CancellationToken token = default);
/// <summary>
/// Time the most recent match ended

View File

@ -163,6 +163,8 @@ namespace SharedLibraryCore
public int Port { get; protected set; }
public int ListenPort => Port;
public abstract Task Kick(string reason, EFClient target, EFClient origin, EFPenalty originalPenalty);
public abstract Task<string[]> ExecuteCommandAsync(string command, CancellationToken token = default);
public abstract Task SetDvarAsync(string name, object value, CancellationToken token = default);
/// <summary>
/// Returns list of all current players