Files
git.stella-ops.org/src/Router/StellaOps.Router.Plugin.Unified/TransportPluginAdapterFactory.cs
2026-02-01 21:37:40 +02:00

158 lines
5.8 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using StellaOps.Plugin.Abstractions;
using StellaOps.Plugin.Abstractions.Capabilities;
using StellaOps.Router.Common.Plugins;
namespace StellaOps.Router.Plugin.Unified;
/// <summary>
/// Factory for creating unified transport plugin adapters from existing router transport plugins.
/// </summary>
public sealed class TransportPluginAdapterFactory
{
private readonly IEnumerable<IRouterTransportPlugin> _plugins;
private readonly Dictionary<string, TransportPluginAdapter> _adapters = new(StringComparer.OrdinalIgnoreCase);
private readonly object _lock = new();
/// <summary>
/// Known transport protocols for each transport type.
/// </summary>
private static readonly Dictionary<string, TransportProtocol> KnownProtocols = new(StringComparer.OrdinalIgnoreCase)
{
["tcp"] = TransportProtocol.Tcp,
["tls"] = TransportProtocol.Tls,
["udp"] = TransportProtocol.Udp,
["rabbitmq"] = TransportProtocol.Amqp,
["valkey"] = TransportProtocol.Redis,
["redis"] = TransportProtocol.Redis,
["inmemory"] = TransportProtocol.InMemory
};
/// <summary>
/// Known features for each transport type.
/// </summary>
private static readonly Dictionary<string, TransportFeatures> KnownFeatures = new(StringComparer.OrdinalIgnoreCase)
{
["tcp"] = TransportFeatures.RequestReply | TransportFeatures.Streaming | TransportFeatures.ConnectionPooling,
["tls"] = TransportFeatures.RequestReply | TransportFeatures.Streaming | TransportFeatures.TlsSupport | TransportFeatures.ConnectionPooling,
["udp"] = TransportFeatures.None, // UDP is connectionless, fire-and-forget
["rabbitmq"] = TransportFeatures.RequestReply | TransportFeatures.PubSub | TransportFeatures.Queuing | TransportFeatures.Acknowledgment | TransportFeatures.AutoReconnect,
["valkey"] = TransportFeatures.PubSub | TransportFeatures.Queuing | TransportFeatures.AutoReconnect,
["redis"] = TransportFeatures.PubSub | TransportFeatures.Queuing | TransportFeatures.AutoReconnect,
["inmemory"] = TransportFeatures.RequestReply | TransportFeatures.Streaming
};
/// <summary>
/// Creates a new factory instance.
/// </summary>
/// <param name="plugins">The available router transport plugins.</param>
public TransportPluginAdapterFactory(IEnumerable<IRouterTransportPlugin> plugins)
{
_plugins = plugins ?? throw new ArgumentNullException(nameof(plugins));
}
/// <summary>
/// Gets all available unified transport plugins.
/// </summary>
/// <param name="serviceProvider">Service provider for availability checking.</param>
/// <returns>List of unified transport plugins.</returns>
public IReadOnlyList<IPlugin> GetAllPlugins(IServiceProvider serviceProvider)
{
var result = new List<IPlugin>();
foreach (var plugin in _plugins)
{
if (plugin.IsAvailable(serviceProvider))
{
var adapter = GetOrCreateAdapter(plugin);
if (adapter != null)
{
result.Add(adapter);
}
}
}
return result;
}
/// <summary>
/// Gets a unified transport plugin by transport name.
/// </summary>
/// <param name="transportName">Transport name (e.g., "tcp", "tls", "rabbitmq").</param>
/// <returns>Unified transport plugin, or null if not found.</returns>
public IPlugin? GetPlugin(string transportName)
{
var plugin = _plugins.FirstOrDefault(p =>
p.TransportName.Equals(transportName, StringComparison.OrdinalIgnoreCase));
if (plugin == null)
{
return null;
}
return GetOrCreateAdapter(plugin);
}
/// <summary>
/// Gets the transport capability for a transport.
/// </summary>
/// <param name="transportName">Transport name.</param>
/// <returns>Transport capability, or null if not found.</returns>
public ITransportCapability? GetCapability(string transportName)
{
return GetPlugin(transportName) as ITransportCapability;
}
/// <summary>
/// Gets all available transport names.
/// </summary>
/// <returns>List of transport names.</returns>
public IReadOnlyList<string> GetAvailableTransports()
{
return _plugins.Select(p => p.TransportName).ToList();
}
private TransportPluginAdapter? GetOrCreateAdapter(IRouterTransportPlugin plugin)
{
lock (_lock)
{
if (_adapters.TryGetValue(plugin.TransportName, out var existing))
{
return existing;
}
var protocol = KnownProtocols.TryGetValue(plugin.TransportName, out var p)
? p
: TransportProtocol.Tcp; // Default to TCP
var features = KnownFeatures.TryGetValue(plugin.TransportName, out var f)
? f
: TransportFeatures.RequestReply; // Default to request/reply
var adapter = new TransportPluginAdapter(plugin, protocol, features);
_adapters[plugin.TransportName] = adapter;
return adapter;
}
}
}
/// <summary>
/// Extension methods for registering unified transport plugin services.
/// </summary>
public static class TransportPluginAdapterExtensions
{
/// <summary>
/// Adds unified transport plugin adapter services to the service collection.
/// </summary>
/// <param name="services">Service collection.</param>
/// <returns>Service collection for chaining.</returns>
public static IServiceCollection AddUnifiedTransportPlugins(this IServiceCollection services)
{
services.AddSingleton<TransportPluginAdapterFactory>();
return services;
}
}