172 lines
6.4 KiB
C#
172 lines
6.4 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Data.Models;
|
|
using IW4MAdmin.Application.Plugin.Script;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using SharedLibraryCore.Interfaces;
|
|
using InteractionRegistrationCallback =
|
|
System.Func<int?, Data.Models.Reference.Game?, System.Threading.CancellationToken,
|
|
System.Threading.Tasks.Task<SharedLibraryCore.Interfaces.IInteractionData>>;
|
|
|
|
namespace IW4MAdmin.Application.Misc;
|
|
|
|
public class InteractionRegistration : IInteractionRegistration
|
|
{
|
|
private readonly ILogger<InteractionRegistration> _logger;
|
|
private readonly IServiceProvider _serviceProvider;
|
|
private readonly ConcurrentDictionary<string, InteractionRegistrationCallback> _interactions = new();
|
|
|
|
public InteractionRegistration(ILogger<InteractionRegistration> logger, IServiceProvider serviceProvider)
|
|
{
|
|
_logger = logger;
|
|
_serviceProvider = serviceProvider;
|
|
}
|
|
|
|
public void RegisterScriptInteraction(string interactionName, string source, Delegate interactionRegistration)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(source))
|
|
{
|
|
throw new ArgumentException("Script interaction source cannot be null");
|
|
}
|
|
|
|
_logger.LogDebug("Registering script interaction {InteractionName} from {Source}", interactionName, source);
|
|
|
|
var plugin = _serviceProvider.GetRequiredService<IEnumerable<IPlugin>>()
|
|
.FirstOrDefault(plugin => plugin.Name == source);
|
|
|
|
if (plugin is not ScriptPlugin scriptPlugin)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Task<IInteractionData> WrappedDelegate(int? clientId, Reference.Game? game, CancellationToken token) =>
|
|
Task.FromResult(
|
|
scriptPlugin.WrapDelegate<IInteractionData>(interactionRegistration, token, clientId, game, token));
|
|
|
|
if (!_interactions.ContainsKey(interactionName))
|
|
{
|
|
_interactions.TryAdd(interactionName, WrappedDelegate);
|
|
}
|
|
else
|
|
{
|
|
_interactions[interactionName] = WrappedDelegate;
|
|
}
|
|
}
|
|
|
|
public void RegisterInteraction(string interactionName, InteractionRegistrationCallback interactionRegistration)
|
|
{
|
|
if (!_interactions.ContainsKey(interactionName))
|
|
{
|
|
_logger.LogDebug("Registering interaction {InteractionName}", interactionName);
|
|
_interactions.TryAdd(interactionName, interactionRegistration);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogDebug("Updating interaction {InteractionName}", interactionName);
|
|
_interactions[interactionName] = interactionRegistration;
|
|
}
|
|
}
|
|
|
|
public void UnregisterInteraction(string interactionName)
|
|
{
|
|
if (!_interactions.ContainsKey(interactionName))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_logger.LogDebug("Unregistering interaction {InteractionName}", interactionName);
|
|
_interactions.TryRemove(interactionName, out _);
|
|
}
|
|
|
|
public async Task<IEnumerable<IInteractionData>> GetInteractions(string interactionPrefix = null,
|
|
int? clientId = null,
|
|
Reference.Game? game = null, CancellationToken token = default)
|
|
{
|
|
return await GetInteractionsInternal(interactionPrefix, clientId, game, token);
|
|
}
|
|
|
|
public async Task<string> ProcessInteraction(string interactionId, int originId, int? targetId = null,
|
|
Reference.Game? game = null, IDictionary<string, string> meta = null, CancellationToken token = default)
|
|
{
|
|
if (!_interactions.ContainsKey(interactionId))
|
|
{
|
|
throw new ArgumentException($"Interaction with ID {interactionId} has not been registered");
|
|
}
|
|
|
|
try
|
|
{
|
|
var interaction = await _interactions[interactionId](targetId, game, token);
|
|
|
|
if (interaction.Action is not null)
|
|
{
|
|
return await interaction.Action(originId, targetId, game, meta, token);
|
|
}
|
|
|
|
if (interaction.ScriptAction is not null)
|
|
{
|
|
foreach (var plugin in _serviceProvider.GetRequiredService<IEnumerable<IPlugin>>())
|
|
{
|
|
if (plugin is not ScriptPlugin scriptPlugin || scriptPlugin.Name != interaction.Source)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return scriptPlugin.ExecuteAction<string>(interaction.ScriptAction, token, originId, targetId, game, meta,
|
|
token);
|
|
}
|
|
|
|
foreach (var plugin in _serviceProvider.GetRequiredService<IEnumerable<IPluginV2>>())
|
|
{
|
|
if (plugin is not ScriptPluginV2 scriptPlugin || scriptPlugin.Name != interaction.Source)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return scriptPlugin
|
|
.QueryWithErrorHandling(interaction.ScriptAction, originId, targetId, game, meta, token)
|
|
?.ToString();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex,
|
|
"Could not process interaction for {InteractionName} and OriginId {ClientId}",
|
|
interactionId, originId);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async Task<IEnumerable<IInteractionData>> GetInteractionsInternal(string prefix = null,
|
|
int? clientId = null, Reference.Game? game = null, CancellationToken token = default)
|
|
{
|
|
var interactions = _interactions
|
|
.Where(interaction => string.IsNullOrWhiteSpace(prefix) || interaction.Key.StartsWith(prefix)).Select(
|
|
async kvp =>
|
|
{
|
|
try
|
|
{
|
|
return await kvp.Value(clientId, game, token);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex,
|
|
"Could not get interaction for {InteractionName} and ClientId {ClientId}",
|
|
kvp.Key,
|
|
clientId);
|
|
return null;
|
|
}
|
|
});
|
|
|
|
return (await Task.WhenAll(interactions))
|
|
.Where(interaction => interaction is not null)
|
|
.ToList();
|
|
}
|
|
}
|