From e9ea621b93fbb58d9edfca8375918791637bbd52 Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 30 Dec 2020 20:59:04 +0800 Subject: +init --- .../src/Impostor.Server/Events/EventManager.cs | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 Impostor-dev/src/Impostor.Server/Events/EventManager.cs (limited to 'Impostor-dev/src/Impostor.Server/Events/EventManager.cs') diff --git a/Impostor-dev/src/Impostor.Server/Events/EventManager.cs b/Impostor-dev/src/Impostor.Server/Events/EventManager.cs new file mode 100644 index 0000000..5625c4d --- /dev/null +++ b/Impostor-dev/src/Impostor.Server/Events/EventManager.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Impostor.Api; +using Impostor.Api.Events; +using Impostor.Api.Events.Managers; +using Impostor.Server.Events.Register; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Impostor.Server.Events +{ + internal class EventManager : IEventManager + { + private readonly ConcurrentDictionary _temporaryEventListeners; + private readonly ConcurrentDictionary> _cachedEventHandlers; + private readonly ILogger _logger; + private readonly IServiceProvider _serviceProvider; + + public EventManager(ILogger logger, IServiceProvider serviceProvider) + { + _logger = logger; + _serviceProvider = serviceProvider; + _temporaryEventListeners = new ConcurrentDictionary(); + _cachedEventHandlers = new ConcurrentDictionary>(); + } + + /// + public IDisposable RegisterListener(TListener listener, Func, Task> invoker = null) + where TListener : IEventListener + { + if (listener == null) + { + throw new ArgumentNullException(nameof(listener)); + } + + var eventListeners = RegisteredEventListener.FromType(listener.GetType()); + var disposes = new IDisposable[eventListeners.Count]; + + foreach (var eventListener in eventListeners) + { + IRegisteredEventListener wrappedEventListener = new WrappedRegisteredEventListener(eventListener, listener); + + if (invoker != null) + { + wrappedEventListener = new InvokedRegisteredEventListener(wrappedEventListener, invoker); + } + + var register = _temporaryEventListeners.GetOrAdd( + wrappedEventListener.EventType, + _ => new TemporaryEventRegister()); + + register.Add(wrappedEventListener); + } + + if (eventListeners.Count > 0) + { + _cachedEventHandlers.TryRemove(typeof(TListener), out _); + } + + return new MultiDisposable(disposes); + } + + /// + public bool IsRegistered() + where TEvent : IEvent + { + if (_cachedEventHandlers.TryGetValue(typeof(TEvent), out var handlers)) + { + return handlers.Count > 0; + } + + return GetHandlers().Any(); + } + + /// + public async ValueTask CallAsync(T @event) + where T : IEvent + { + try + { + if (!_cachedEventHandlers.TryGetValue(typeof(T), out var handlers)) + { + handlers = CacheEventHandlers(); + } + + foreach (var (handler, eventListener) in handlers) + { + await eventListener.InvokeAsync(handler, @event, _serviceProvider); + } + } + catch (ImpostorCheatException) + { + throw; + } + catch (Exception e) + { + _logger.LogError(e, "Invocation of event {0} threw an exception.", @event.GetType().Name); + } + } + + private List CacheEventHandlers() + where TEvent : IEvent + { + var handlers = GetHandlers() + .OrderByDescending(e => e.Listener.Priority) + .ToList(); + + _cachedEventHandlers[typeof(TEvent)] = handlers; + + return handlers; + } + + /// + /// Get all the event listeners for the given event type. + /// + /// The event listeners. + private IEnumerable GetHandlers() + where TEvent : IEvent + { + var eventType = typeof(TEvent); + var interfaces = eventType.GetInterfaces(); + + foreach (var @interface in interfaces) + { + if (_temporaryEventListeners.TryGetValue(@interface, out var cb)) + { + foreach (var eventListener in cb.GetEventListeners()) + { + yield return new EventHandler(null, eventListener); + } + } + } + + foreach (var handler in _serviceProvider.GetServices()) + { + if (handler is IManualEventListener manualEventListener && manualEventListener.CanExecute()) + { + yield return new EventHandler(handler, new ManualRegisteredEventListener(manualEventListener)); + continue; + } + + var events = RegisteredEventListener.FromType(handler.GetType()); + + foreach (var eventHandler in events) + { + if (eventHandler.EventType != typeof(TEvent) && !interfaces.Contains(eventHandler.EventType)) + { + continue; + } + + yield return new EventHandler(handler, eventHandler); + } + } + + if (_temporaryEventListeners.TryGetValue(eventType, out var cb2)) + { + foreach (var eventListener in cb2.GetEventListeners()) + { + yield return new EventHandler(null, eventListener); + } + } + } + } +} -- cgit v1.1-26-g67d0