You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework/Connected.Middleware/MiddlewareService.cs

233 lines
4.9 KiB

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 });
}
}
}
}