using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using MessagePipe.Internal; #if !UNITY_2018_3_OR_NEWER using Microsoft.Extensions.DependencyInjection; #endif namespace MessagePipe { public enum AsyncPublishStrategy { Parallel, Sequential } public enum InstanceLifetime { Singleton, Scoped, Transient } public enum HandlingSubscribeDisposedPolicy { Ignore, Throw } internal static class HandlingSubscribeDisposedPolicyExtensions { public static IDisposable Handle(this HandlingSubscribeDisposedPolicy policy, string name) { if (policy == HandlingSubscribeDisposedPolicy.Throw) { throw new ObjectDisposedException(name); } return DisposableBag.Empty; } } public sealed class MessagePipeOptions { /// AsyncPublisher.PublishAsync's concurrent starategy, default is Parallel. public AsyncPublishStrategy DefaultAsyncPublishStrategy { get; set; } #if !UNITY_2018_3_OR_NEWER public bool EnableAutoRegistration { get; set; } #endif /// For diagnostics usage, enable MessagePipeDiagnosticsInfo.CapturedStacktraces; default is false. public bool EnableCaptureStackTrace { get; set; } /// Choose how work on subscriber.Subscribe when after disposed, default is Ignore. public HandlingSubscribeDisposedPolicy HandlingSubscribeDisposedPolicy { get; set; } /// Default publisher/subscribe's lifetime scope, default is Singleton. public InstanceLifetime InstanceLifetime { get; set; } /// Default IRequestHandler/IAsyncRequestHandler's lifetime scope, default is Scoped. public InstanceLifetime RequestHandlerLifetime { get; set; } public MessagePipeOptions() { this.DefaultAsyncPublishStrategy = AsyncPublishStrategy.Parallel; this.InstanceLifetime = InstanceLifetime.Singleton; this.RequestHandlerLifetime = InstanceLifetime.Scoped; this.EnableCaptureStackTrace = false; this.HandlingSubscribeDisposedPolicy = HandlingSubscribeDisposedPolicy.Ignore; #if !UNITY_2018_3_OR_NEWER this.EnableAutoRegistration = true; this.autoregistrationAssemblies = null; this.autoregistrationTypes = null; #endif } #if !UNITY_2018_3_OR_NEWER // auto-registration internal Assembly[] autoregistrationAssemblies; internal Type[] autoregistrationTypes; public void SetAutoRegistrationSearchAssemblies(params Assembly[] assemblies) { autoregistrationAssemblies = assemblies; } public void SetAutoRegistrationSearchTypes(params Type[] types) { autoregistrationTypes = types; } #endif // filters internal IEnumerable GetGlobalFilterTypes() { foreach (var item in messageHandlerFilters) { yield return item.FilterType; } foreach (var item in asyncMessageHandlerFilters) { yield return item.FilterType; } foreach (var item in requestHandlerFilters) { yield return item.FilterType; } foreach (var item in asyncRequestHandlerFilters) { yield return item.FilterType; } } // MessageHandlerFilter List messageHandlerFilters = new List(); #if !UNITY_2018_3_OR_NEWER /// /// If register open generics(typeof(MyFilter<>)) to register all message types. /// public void AddGlobalMessageHandlerFilter(Type type, int order = 0) { ValidateFilterType(type, typeof(IMessageHandlerFilter)); messageHandlerFilters.Add(new MessageHandlerFilterDefinition(type, order, typeof(MessageHandlerFilter<>))); } #endif public void AddGlobalMessageHandlerFilter(int order = 0) where T : IMessageHandlerFilter { messageHandlerFilters.Add(new MessageHandlerFilterDefinition(typeof(T), order, typeof(MessageHandlerFilter<>))); } internal (int count, IEnumerable) GetGlobalMessageHandlerFilters(IServiceProvider provider, Type messageType) { return (messageHandlerFilters.Count, CreateFilters(messageHandlerFilters, provider, messageType)); } // AsyncMessageHandlerFilter List asyncMessageHandlerFilters = new List(); #if !UNITY_2018_3_OR_NEWER /// /// If register open generics(typeof(MyFilter<>)) to register all message types. /// public void AddGlobalAsyncMessageHandlerFilter(Type type, int order = 0) { ValidateFilterType(type, typeof(IAsyncMessageHandlerFilter)); asyncMessageHandlerFilters.Add(new MessageHandlerFilterDefinition(type, order, typeof(AsyncMessageHandlerFilter<>))); } #endif public void AddGlobalAsyncMessageHandlerFilter(int order = 0) where T : IAsyncMessageHandlerFilter { asyncMessageHandlerFilters.Add(new MessageHandlerFilterDefinition(typeof(T), order, typeof(AsyncMessageHandlerFilter<>))); } internal (int count, IEnumerable) GetGlobalAsyncMessageHandlerFilters(IServiceProvider provider, Type messageType) { return (asyncMessageHandlerFilters.Count, CreateFilters(asyncMessageHandlerFilters, provider, messageType)); } // RequestHandlerFilter List requestHandlerFilters = new List(); #if !UNITY_2018_3_OR_NEWER /// /// If register open generics(typeof(MyFilter<>)) to register all message types. /// public void AddGlobalRequestHandlerFilter(Type type, int order = 0) { ValidateFilterType(type, typeof(IRequestHandlerFilter)); requestHandlerFilters.Add(new RequestHandlerFilterDefinition(type, order, typeof(RequestHandlerFilter<,>))); } #endif public void AddGlobalRequestHandlerFilter(int order = 0) where T : IRequestHandlerFilter { requestHandlerFilters.Add(new RequestHandlerFilterDefinition(typeof(T), order, typeof(RequestHandlerFilter<,>))); } internal (int, IEnumerable) GetGlobalRequestHandlerFilters(IServiceProvider provider, Type requestType, Type responseType) { return (requestHandlerFilters.Count, CreateFilters(requestHandlerFilters, provider, requestType, responseType)); } // AsyncRequestHandlerFilter List asyncRequestHandlerFilters = new List(); #if !UNITY_2018_3_OR_NEWER /// /// If register open generics(typeof(MyFilter<>)) to register all message types. /// public void AddGlobalAsyncRequestHandlerFilter(Type type, int order = 0) { ValidateFilterType(type, typeof(IAsyncRequestHandlerFilter)); asyncRequestHandlerFilters.Add(new RequestHandlerFilterDefinition(type, order, typeof(AsyncRequestHandlerFilter<,>))); } #endif public void AddGlobalAsyncRequestHandlerFilter(int order = 0) where T : IAsyncRequestHandlerFilter { asyncRequestHandlerFilters.Add(new RequestHandlerFilterDefinition(typeof(T), order, typeof(AsyncRequestHandlerFilter<,>))); } internal (int, IEnumerable) GetGlobalAsyncRequestHandlerFilters(IServiceProvider provider, Type requestType, Type responseType) { return (asyncRequestHandlerFilters.Count, CreateFilters(asyncRequestHandlerFilters, provider, requestType, responseType)); } static IEnumerable CreateFilters(List filterDefinitions, IServiceProvider provider, Type messageType) where T : IMessagePipeFilter { if (filterDefinitions.Count == 0) return Array.Empty(); return CreateFiltersCore(filterDefinitions, provider, messageType); } static IEnumerable CreateFiltersCore(List filterDefinitions, IServiceProvider provider, Type messageType) where T : IMessagePipeFilter { for (int i = 0; i < filterDefinitions.Count; i++) { var def = filterDefinitions[i] as MessageHandlerFilterDefinition; if (def == null) continue; var filterType = def.FilterType; if (def.IsOpenGenerics) { filterType = filterType.MakeGenericType(messageType); } else if (def.MessageType != messageType) { continue; } var filter = (T)provider.GetRequiredService(filterType); filter.Order = def.Order; yield return filter; } } static IEnumerable CreateFilters(List filterDefinitions, IServiceProvider provider, Type requestType, Type responseType) where T : IMessagePipeFilter { if (filterDefinitions.Count == 0) return Array.Empty(); return CreateFiltersCore(filterDefinitions, provider, requestType, responseType); } static IEnumerable CreateFiltersCore(List filterDefinitions, IServiceProvider provider, Type requestType, Type responseType) where T : IMessagePipeFilter { for (int i = 0; i < filterDefinitions.Count; i++) { var def = filterDefinitions[i] as RequestHandlerFilterDefinition; if (def == null) continue; var filterType = def.FilterType; if (def.IsOpenGenerics) { filterType = filterType.MakeGenericType(requestType, responseType); } else if (!(def.RequestType == requestType && def.ResponseType == responseType)) { continue; } var filter = (T)provider.GetRequiredService(filterType); filter.Order = def.Order; yield return filter; } } void ValidateFilterType(Type type, Type filterType) { if (!filterType.IsAssignableFrom(type)) { throw new ArgumentException($"{type.FullName} is not {filterType.Name}"); } } } }