using Microsoft.Extensions.DependencyInjection; using System.Reflection; namespace Toolkit.Foundation; public class Publisher(ISubscriptionManager subscriptionManager, IServiceProvider provider, IDispatcher dispatcher) : IPublisher { public Task Publish(object key, CancellationToken cancellationToken = default) where TMessage : new() => Publish(new TMessage(), async args => await args(), key, cancellationToken); public Task Publish(TMessage message, CancellationToken cancellationToken = default) where TMessage : notnull => Publish(message, async args => await args(), null, cancellationToken); public Task Publish(TMessage message, object key, CancellationToken cancellationToken = default) where TMessage : notnull => Publish(message, async args => await args(), key, cancellationToken); public async Task Publish(object message, Func, Task> marshal, object? key = null, CancellationToken cancellationToken = default) { Type notificationType = message.GetType(); List handlers = provider.GetServices(typeof(NotificationHandlerWrapper<>) .MakeGenericType(notificationType)).ToList(); foreach (object? handler in subscriptionManager .GetHandlers(notificationType, key!)) { handlers.Add(handler); } foreach (object? handler in handlers) { if (handler is not null) { Type? handlerType = handler.GetType(); MethodInfo? handleMethod = handlerType.GetMethod("Handle", [notificationType, typeof(CancellationToken)]); if (handleMethod is not null) { await marshal(() => (Task)handleMethod.Invoke(handler, new object[] { message, cancellationToken })!); } } } } public Task Publish(object message, CancellationToken cancellationToken = default) => Publish(message, async args => await args(), null, cancellationToken); public Task Publish(CancellationToken cancellationToken = default) where TMessage : new() => Publish(new TMessage(), async args => await args(), null, cancellationToken); public Task PublishUI(object key, CancellationToken cancellationToken = default) where TMessage : new() => Publish(new TMessage(), args => dispatcher.Invoke(async () => await args()), key, cancellationToken); public Task PublishUI(TMessage message, CancellationToken cancellationToken = default) where TMessage : notnull => Publish(message, args => dispatcher.Invoke(async () => await args()), null, cancellationToken); public Task PublishUI(TMessage message, object key, CancellationToken cancellationToken = default) where TMessage : notnull => Publish(message, args => dispatcher.Invoke(async () => await args()), key, cancellationToken); public Task PublishUI(CancellationToken cancellationToken = default) where TMessage : new() => Publish(new TMessage(), args => dispatcher.Invoke(async () => await args()), null, cancellationToken); public Task PublishUI(object message, CancellationToken cancellationToken = default) => Publish(message, args => dispatcher.Invoke(async () => await args()), null, cancellationToken); }