using MessagePipe.Internal; using System; using System.Runtime.CompilerServices; namespace MessagePipe { [Preserve] public class MessageBroker : IPublisher, ISubscriber { readonly MessageBrokerCore core; readonly FilterAttachedMessageHandlerFactory handlerFactory; [Preserve] public MessageBroker(MessageBrokerCore core, FilterAttachedMessageHandlerFactory handlerFactory) { this.core = core; this.handlerFactory = handlerFactory; } public void Publish(TMessage message) { core.Publish(message); } public IDisposable Subscribe(IMessageHandler handler, params MessageHandlerFilter[] filters) { return core.Subscribe(handlerFactory.CreateMessageHandler(handler, filters)); } } [Preserve] public class MessageBrokerCore : IDisposable, IHandlerHolderMarker { readonly FreeList> handlers; readonly MessagePipeDiagnosticsInfo diagnostics; readonly HandlingSubscribeDisposedPolicy handlingSubscribeDisposedPolicy; readonly object gate = new object(); bool isDisposed; [Preserve] public MessageBrokerCore(MessagePipeDiagnosticsInfo diagnostics, MessagePipeOptions options) { this.handlers = new FreeList>(); this.handlingSubscribeDisposedPolicy = options.HandlingSubscribeDisposedPolicy; this.diagnostics = diagnostics; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Publish(TMessage message) { var array = handlers.GetValues(); for (int i = 0; i < array.Length; i++) { array[i]?.Handle(message); } } public IDisposable Subscribe(IMessageHandler handler) { lock (gate) { if (isDisposed) return handlingSubscribeDisposedPolicy.Handle(nameof(MessageBrokerCore)); var subscriptionKey = handlers.Add(handler); var subscription = new Subscription(this, subscriptionKey); diagnostics.IncrementSubscribe(this, subscription); return subscription; } } public void Dispose() { lock (gate) { // Dispose is called when scope is finished. if (!isDisposed && handlers.TryDispose(out var count)) { isDisposed = true; diagnostics.RemoveTargetDiagnostics(this, count); } } } sealed class Subscription : IDisposable { bool isDisposed; readonly MessageBrokerCore core; readonly int subscriptionKey; public Subscription(MessageBrokerCore core, int subscriptionKey) { this.core = core; this.subscriptionKey = subscriptionKey; } public void Dispose() { if (!isDisposed) { isDisposed = true; lock (core.gate) { if (!core.isDisposed) { core.handlers.Remove(subscriptionKey, true); core.diagnostics.DecrementSubscribe(core, this); } } } } } } [Preserve] public sealed class BufferedMessageBroker : IBufferedPublisher, IBufferedSubscriber { readonly BufferedMessageBrokerCore core; readonly FilterAttachedMessageHandlerFactory handlerFactory; [Preserve] public BufferedMessageBroker(BufferedMessageBrokerCore core, FilterAttachedMessageHandlerFactory handlerFactory) { this.core = core; this.handlerFactory = handlerFactory; } public void Publish(TMessage message) { core.Publish(message); } public IDisposable Subscribe(IMessageHandler handler, params MessageHandlerFilter[] filters) { return core.Subscribe(handlerFactory.CreateMessageHandler(handler, filters)); } } [Preserve] public sealed class BufferedMessageBrokerCore { static readonly bool IsValueType = typeof(TMessage).IsValueType; readonly MessageBrokerCore core; TMessage lastMessage; [Preserve] public BufferedMessageBrokerCore(MessageBrokerCore core) { this.core = core; this.lastMessage = default; } public void Publish(TMessage message) { lastMessage = message; core.Publish(message); } public IDisposable Subscribe(IMessageHandler handler) { if (IsValueType || lastMessage != null) { handler.Handle(lastMessage); } return core.Subscribe(handler); } } // Singleton, Scoped variation [Preserve] public class SingletonMessageBroker : MessageBroker, ISingletonPublisher, ISingletonSubscriber { [Preserve] public SingletonMessageBroker(SingletonMessageBrokerCore core, FilterAttachedMessageHandlerFactory handlerFactory) : base(core, handlerFactory) { } } [Preserve] public class ScopedMessageBroker : MessageBroker, IScopedPublisher, IScopedSubscriber { [Preserve] public ScopedMessageBroker(ScopedMessageBrokerCore core, FilterAttachedMessageHandlerFactory handlerFactory) : base(core, handlerFactory) { } } [Preserve] public class SingletonMessageBrokerCore : MessageBrokerCore { [Preserve] public SingletonMessageBrokerCore(MessagePipeDiagnosticsInfo diagnostics, MessagePipeOptions options) : base(diagnostics, options) { } } [Preserve] public class ScopedMessageBrokerCore : MessageBrokerCore { [Preserve] public ScopedMessageBrokerCore(MessagePipeDiagnosticsInfo diagnostics, MessagePipeOptions options) : base(diagnostics, options) { } } }