|
|
|
|
using Connected.Collections;
|
|
|
|
|
using Connected.Configuration.Environment;
|
|
|
|
|
using Connected.Interop;
|
|
|
|
|
using Connected.Middleware.Annotations;
|
|
|
|
|
using Connected.ServiceModel;
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
using System.Collections.Immutable;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
namespace Connected.Middleware;
|
|
|
|
|
|
|
|
|
|
internal class MiddlewareService : IMiddlewareService
|
|
|
|
|
{
|
|
|
|
|
private static readonly object _lock = new();
|
|
|
|
|
|
|
|
|
|
static MiddlewareService()
|
|
|
|
|
{
|
|
|
|
|
Endpoints = new();
|
|
|
|
|
}
|
|
|
|
|
public MiddlewareService(IEnvironmentService environmentService, IContext context)
|
|
|
|
|
{
|
|
|
|
|
EnvironmentService = environmentService;
|
|
|
|
|
Context = context;
|
|
|
|
|
|
|
|
|
|
if (!IsInitialized)
|
|
|
|
|
{
|
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
if (!IsInitialized)
|
|
|
|
|
Initialize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool IsInitialized { get; set; }
|
|
|
|
|
private IEnvironmentService EnvironmentService { get; }
|
|
|
|
|
private IContext Context { get; }
|
|
|
|
|
private static ConcurrentDictionary<string, List<Type>> Endpoints { get; set; }
|
|
|
|
|
|
|
|
|
|
public async Task<ImmutableList<TEndpoint>> Query<TEndpoint>() where TEndpoint : IMiddleware
|
|
|
|
|
{
|
|
|
|
|
return await Query<TEndpoint>(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<ImmutableList<IMiddleware>> Query(Type type)
|
|
|
|
|
{
|
|
|
|
|
return await Query(type, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<ImmutableList<TEndpoint>> Query<TEndpoint>(ICallerContext? context) where TEndpoint : IMiddleware
|
|
|
|
|
{
|
|
|
|
|
var key = typeof(TEndpoint).FullName;
|
|
|
|
|
|
|
|
|
|
if (key is null || Endpoints is null)
|
|
|
|
|
return ImmutableList<TEndpoint>.Empty;
|
|
|
|
|
|
|
|
|
|
if (!Endpoints.TryGetValue(key, out List<Type>? items) || items is null)
|
|
|
|
|
return ImmutableList<TEndpoint>.Empty;
|
|
|
|
|
|
|
|
|
|
var result = new List<TEndpoint>();
|
|
|
|
|
|
|
|
|
|
foreach (var type in items)
|
|
|
|
|
{
|
|
|
|
|
if (!Validate(context, type))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Context.GetService(type) is object service)
|
|
|
|
|
result.Add((TEndpoint)service);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.SortByPriority();
|
|
|
|
|
|
|
|
|
|
foreach (var r in result)
|
|
|
|
|
await r.Initialize();
|
|
|
|
|
|
|
|
|
|
return result.ToImmutableList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<ImmutableList<IMiddleware>> Query(Type type, ICallerContext? context)
|
|
|
|
|
{
|
|
|
|
|
var key = type.FullName;
|
|
|
|
|
|
|
|
|
|
if (key is null || Endpoints is null)
|
|
|
|
|
return ImmutableList<IMiddleware>.Empty;
|
|
|
|
|
|
|
|
|
|
if (!Endpoints.TryGetValue(key, out List<Type>? items) || items is null)
|
|
|
|
|
return ImmutableList<IMiddleware>.Empty;
|
|
|
|
|
|
|
|
|
|
var result = new List<IMiddleware>();
|
|
|
|
|
|
|
|
|
|
foreach (var t in items)
|
|
|
|
|
{
|
|
|
|
|
if (!Validate(context, t))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Context.GetService(type) is IMiddleware service)
|
|
|
|
|
result.Add(service);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.SortByPriority();
|
|
|
|
|
|
|
|
|
|
foreach (var r in result)
|
|
|
|
|
await r.Initialize();
|
|
|
|
|
|
|
|
|
|
return result.ToImmutableList();
|
|
|
|
|
}
|
|
|
|
|
public async Task<TEndpoint?> First<TEndpoint>()
|
|
|
|
|
where TEndpoint : IMiddleware
|
|
|
|
|
{
|
|
|
|
|
var key = typeof(TEndpoint).FullName;
|
|
|
|
|
|
|
|
|
|
if (key is null || Endpoints is null)
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
if (!Endpoints.TryGetValue(key, out List<Type>? items) || items is null)
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
var types = new List<Type>();
|
|
|
|
|
|
|
|
|
|
foreach (var type in items)
|
|
|
|
|
types.Add(type);
|
|
|
|
|
|
|
|
|
|
if (!types.Any())
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
types.SortByPriority();
|
|
|
|
|
|
|
|
|
|
foreach (var type in types)
|
|
|
|
|
{
|
|
|
|
|
if (!Validate(null, type))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Context.GetService(type) is object service)
|
|
|
|
|
{
|
|
|
|
|
var r = (TEndpoint)service;
|
|
|
|
|
await r.Initialize();
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IMiddleware?> First(Type type)
|
|
|
|
|
{
|
|
|
|
|
var key = type.FullName;
|
|
|
|
|
|
|
|
|
|
if (key is null || Endpoints is null)
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
if (!Endpoints.TryGetValue(key, out List<Type>? items) || items is null)
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
var types = new List<Type>();
|
|
|
|
|
|
|
|
|
|
foreach (var t in items)
|
|
|
|
|
types.Add(t);
|
|
|
|
|
|
|
|
|
|
if (!types.Any())
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
types.SortByPriority();
|
|
|
|
|
|
|
|
|
|
foreach (var t in types)
|
|
|
|
|
{
|
|
|
|
|
if (!Validate(null, t))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Context.GetService(t) is IMiddleware service)
|
|
|
|
|
{
|
|
|
|
|
await service.Initialize();
|
|
|
|
|
|
|
|
|
|
return service;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool Validate(ICallerContext? context, Type type)
|
|
|
|
|
{
|
|
|
|
|
if (context is null)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
var attributes = type.GetCustomAttributes();
|
|
|
|
|
|
|
|
|
|
foreach (var attribute in attributes)
|
|
|
|
|
{
|
|
|
|
|
if (attribute.GetType() != typeof(MiddlewareAttribute<>))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var method = attribute.GetType().GetProperty(nameof(MiddlewareAttribute<object>.ComponentMethod));
|
|
|
|
|
|
|
|
|
|
if (method is null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!string.Equals(TypeConversion.Convert<string>(method.GetValue(attribute)), context.Method, StringComparison.Ordinal))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var argument = attribute.GetType().GetGenericArguments()[0];
|
|
|
|
|
|
|
|
|
|
if (argument != context.Sender?.GetType())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Initialize()
|
|
|
|
|
{
|
|
|
|
|
IsInitialized = true;
|
|
|
|
|
|
|
|
|
|
foreach (var endpoint in EnvironmentService.Services.IoCEndpoints)
|
|
|
|
|
{
|
|
|
|
|
var endpoints = endpoint.GetImplementedMiddleware();
|
|
|
|
|
|
|
|
|
|
foreach (var ep in endpoints)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(ep.FullName))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (Endpoints.TryGetValue(ep.FullName, out List<Type>? list))
|
|
|
|
|
list.Add(endpoint);
|
|
|
|
|
else
|
|
|
|
|
Endpoints.TryAdd(ep.FullName, new List<Type> { endpoint });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|