public void AddPermissionCheckProvider(Type type) { if (!typeof(IPermissionCheckProvider).IsAssignableFrom(type)) { throw new Exception($"Type {type} must be an instance of IPermissionCheckProvider!"); } if (m_PermissionCheckProviderTypes.Contains(type)) { return; } m_PermissionCheckProviderTypes.Add(type); m_PermissionCheckProviderTypes.Sort((a, b) => m_PriorityComparer.Compare(a.GetPriority(), b.GetPriority())); }
public async Task <IReadOnlyCollection <ICommandRegistration> > GetCommandsAsync() { if (m_IsDisposing) { throw new ObjectDisposedException(nameof(CommandStore)); } var commands = new List <ICommandRegistration>(); foreach (var sources in m_CommandSources) { foreach (var command in await sources.GetCommandsAsync()) { if (!command.Component.IsComponentAlive) { continue; } var commandData = await GetOrCreateCommandData(command); commands.Add(new RegisteredCommand(command, commandData)); } } commands.Sort((a, b) => m_Comparer.Compare(a.Priority, b.Priority)); return(commands); }
public virtual async Task EmitAsync(IOpenModComponent component, object sender, IEvent @event, EventExecutedCallback callback = null) { if (!component.IsComponentAlive) { return; } m_Logger.LogTrace($"Emitting event: {@event.Name}"); var eventSubscriptions = m_EventSubscriptions .Where(c => (c.EventType != null && c.EventType.IsInstanceOfType(@event)) || (@event.Name.Equals(c.EventName, StringComparison.OrdinalIgnoreCase) && c.Owner.IsAlive && ((IOpenModComponent)c.Owner.Target).IsComponentAlive)) .ToList(); void Complete() { m_Logger.LogTrace($"{@event.Name}: Finished."); callback?.Invoke(@event); } if (eventSubscriptions.Count == 0) { m_Logger?.LogTrace($"{@event.Name}: No listeners found."); Complete(); return; } var comparer = new PriorityComparer(PriortyComparisonMode.LowestFirst); eventSubscriptions.Sort((a, b) => comparer.Compare(a.EventListenerAttribute.Priority, b.EventListenerAttribute.Priority)); foreach (var group in eventSubscriptions.GroupBy(e => e.Scope)) { await using var newScope = group.Key.BeginLifetimeScope("AutofacWebRequest"); foreach (var subscription in group) { if (@event is ICancellableEvent cancellableEvent && cancellableEvent.IsCancelled && !subscription.EventListenerAttribute.IgnoreCancelled) { continue; } var serviceProvider = newScope.Resolve <IServiceProvider>(); try { await subscription.Callback.Invoke(serviceProvider, sender, @event); } catch (Exception ex) { m_Logger.LogError(ex, $"Exception occured during event {@event.Name}"); } } } Complete(); }
public void Should_return_0_for_other_case() { // Arrange var comparer = new PriorityComparer <GenericPriorityMessage <int> >(); var m1 = new GenericPriorityMessage <int>(1, 0); var m2 = new GenericPriorityMessage <int>(1, 0); // Action & Assert Assert.AreEqual(0, comparer.Compare(m2, m1)); }
public void Should_return_minus_1_if_object_on_the_left_has_lower_priority_value() { // Arrange var comparer = new PriorityComparer <GenericPriorityMessage <int> >(); var m1 = new GenericPriorityMessage <int>(1, 10); var m2 = new GenericPriorityMessage <int>(1, 0); // Action & Assert Assert.AreEqual(-1, comparer.Compare(m2, m1)); }
public void Should_return_0_for_other_case() { // Arrange var comparer = new PriorityComparer<GenericPriorityMessage<int>>(); var m1 = new GenericPriorityMessage<int>(1, 0); var m2 = new GenericPriorityMessage<int>(1, 0); // Action & Assert Assert.AreEqual(0, comparer.Compare(m2, m1)); }
public void Should_return_minus_1_if_object_on_the_left_has_lower_priority_value() { // Arrange var comparer = new PriorityComparer<GenericPriorityMessage<int>>(); var m1 = new GenericPriorityMessage<int>(1, 10); var m2 = new GenericPriorityMessage<int>(1, 0); // Action & Assert Assert.AreEqual(-1, comparer.Compare(m2, m1)); }
public virtual async Task EmitAsync(IOpenModComponent component, object sender, IEvent @event, EventExecutedCallback callback = null) { if (!component.IsComponentAlive) { return; } m_Logger.LogTrace($"Emitting event: {@event.Name}"); var eventSubscriptions = m_EventSubscriptions .Where(c => (c.EventType != null && c.EventType.IsInstanceOfType(@event)) || (@event.Name.Equals(c.EventName, StringComparison.OrdinalIgnoreCase) && c.Owner.IsAlive && ((IOpenModComponent)c.Owner.Target).IsComponentAlive)) .ToList(); void Complete() { m_Logger.LogTrace($"{@event.Name}: Finished."); callback?.Invoke(@event); } if (eventSubscriptions.Count == 0) { m_Logger?.LogTrace($"{@event.Name}: No listeners found."); Complete(); return; } var comparer = new PriorityComparer(PriortyComparisonMode.LowestFirst); eventSubscriptions.Sort((a, b) => comparer.Compare(a.EventListenerAttribute.Priority, b.EventListenerAttribute.Priority)); foreach (var subscription in eventSubscriptions) { var owner = subscription.Owner; if (!owner.IsAlive || !((IOpenModComponent)owner.Target).IsComponentAlive) { m_EventSubscriptions.Remove(subscription); continue; } if (@event is ICancellableEvent cancellableEvent && cancellableEvent.IsCancelled && !subscription.EventListenerAttribute.IgnoreCancelled) { continue; } var serviceProvider = subscription.Scope.Resolve <IServiceProvider>(); await subscription.Callback.Invoke(serviceProvider, sender, @event); } Complete(); }
public void Should_return_minus_1_if_object_on_the_left_is_younger_than_the_other_one() { // Arrange var comparer = new PriorityComparer<GenericPriorityMessage<int>>(); var m1 = new GenericPriorityMessage<int>(1, 0); System.Threading.Thread.Sleep(1); var m2 = new GenericPriorityMessage<int>(1, 0); // Action & Assert Assert.AreEqual(-1, comparer.Compare(m2, m1)); }
public void Should_return_minus_1_if_object_on_the_left_is_younger_than_the_other_one() { // Arrange var comparer = new PriorityComparer <GenericPriorityMessage <int> >(); var m1 = new GenericPriorityMessage <int>(1, 0); System.Threading.Thread.Sleep(1); var m2 = new GenericPriorityMessage <int>(1, 0); // Action & Assert Assert.AreEqual(-1, comparer.Compare(m2, m1)); }
public void AddJobExecutor(Type type) { if (!typeof(ITaskExecutor).IsAssignableFrom(type)) { throw new Exception($"Type {type} must be an instance of IJobExecutor!"); } if (m_JobExecutorTypes.Contains(type)) { return; } m_JobExecutorTypes.Add(type); m_JobExecutorTypes.Sort((a, b) => m_PriorityComparer.Compare(a.GetPriority(), b.GetPriority())); }
public void AddCommandSource(Type type) { if (!typeof(ICommandSource).IsAssignableFrom(type)) { throw new Exception($"Type {type} must be an instance of ICommandSource!"); } if (m_CommandSourceTypes.Contains(type)) { return; } m_CommandSourceTypes.Add(type); m_CommandSourceTypes.Sort((a, b) => m_PriorityComparer.Compare(a.GetPriority(), b.GetPriority())); }
public void AddCommandParameterResolveProvider(Type type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (!typeof(ICommandParameterResolveProvider).IsAssignableFrom(type)) { throw new ArgumentException($"Type {type} must be an instance of {nameof(ICommandParameterResolveProvider)}!", nameof(type)); } if (m_CommandParameterResolveProviderTypes.Contains(type)) { return; } m_CommandParameterResolveProviderTypes.Add(type); m_CommandParameterResolveProviderTypes.Sort((a, b) => m_PriorityComparer.Compare(a.GetPriority(), b.GetPriority())); }
public virtual async Task EmitAsync(IOpenModComponent component, object sender, IEvent @event, EventExecutedCallback callback = null) { if (!component.IsComponentAlive) { return; } var eventTypes = new List <Type>(); var currentType = @event.GetType(); while (currentType != null && typeof(IEvent).IsAssignableFrom(currentType)) { eventTypes.Add(currentType); currentType = currentType.BaseType; } eventTypes.AddRange(@event.GetType().GetInterfaces().Where(d => typeof(IEvent).IsAssignableFrom(d))); foreach (var eventType in eventTypes.Except(s_OmittedTypes)) { string eventName = GetEventName(eventType); m_Logger.LogTrace($"Emitting event: {eventName}"); var eventSubscriptions = m_EventSubscriptions .Where(c => (c.EventType != null && c.EventType == eventType) || (eventName.Equals(c.EventName, StringComparison.OrdinalIgnoreCase) && c.Owner.IsAlive && ((IOpenModComponent)c.Owner.Target).IsComponentAlive)) .ToList(); if (eventSubscriptions.Count == 0) { continue; } var comparer = new PriorityComparer(PriortyComparisonMode.LowestFirst); eventSubscriptions.Sort((a, b) => comparer.Compare( (Priority)a.EventListenerAttribute.Priority, (Priority)b.EventListenerAttribute.Priority) ); foreach (var group in eventSubscriptions.GroupBy(e => e.Scope)) { await using var newScope = group.Key.BeginLifetimeScope("AutofacWebRequest"); foreach (var subscription in group) { var cancellableEvent = @event as ICancellableEvent; if (cancellableEvent != null && cancellableEvent.IsCancelled && !subscription.EventListenerAttribute.IgnoreCancelled) { continue; } var wasCancelled = false; if (cancellableEvent != null) { wasCancelled = cancellableEvent.IsCancelled; } var serviceProvider = newScope.Resolve <IServiceProvider>(); try { await subscription.Callback.Invoke(serviceProvider, sender, @event); if (cancellableEvent != null && subscription.EventListenerAttribute.Priority == EventListenerPriority.Monitor) { if (cancellableEvent.IsCancelled != wasCancelled) { cancellableEvent.IsCancelled = wasCancelled; m_Logger.LogWarning( $"{((IOpenModComponent)@subscription.Owner.Target).OpenModComponentId} changed {@eventName} cancellation status with Monitor priority which is not permitted."); } } } catch (Exception ex) { m_Logger.LogError(ex, $"Exception occured during event {@eventName}"); } } } m_Logger.LogTrace($"{eventName}: Finished."); } callback?.Invoke(@event); }
public virtual async Task EmitAsync(IOpenModComponent component, object?sender, IEvent @event, EventExecutedCallback?callback = null) { if (component == null) { throw new ArgumentNullException(nameof(component)); } if (@event == null) { throw new ArgumentNullException(nameof(@event)); } if (!component.IsComponentAlive) { m_Logger.LogDebug($"EmitAsync called by {component.OpenModComponentId} for {@event.GetType().Name} but the component is not alive."); return; } var eventTypes = new List <Type>(); var currentType = @event.GetType(); while (currentType != null && typeof(IEvent).IsAssignableFrom(currentType)) { eventTypes.Add(currentType); currentType = currentType.BaseType; } eventTypes.AddRange(@event.GetType().GetInterfaces().Where(d => typeof(IEvent).IsAssignableFrom(d))); foreach (var eventType in eventTypes.Except(s_OmittedTypes)) { string eventName = GetEventName(eventType); m_Logger.LogTrace($"Emitting event: {eventName}"); var eventSubscriptions = m_EventSubscriptions .Where(c => (c.EventType != null && c.EventType == eventType) || (eventName.Equals(c.EventName, StringComparison.OrdinalIgnoreCase) && c.Owner.IsAlive && ((IOpenModComponent)c.Owner.Target).IsComponentAlive)) .ToList(); if (eventSubscriptions.Count == 0) { m_Logger.LogTrace($"No event subscriptions found for: {eventName}"); continue; } var comparer = new PriorityComparer(PriortyComparisonMode.LowestFirst); eventSubscriptions.Sort((a, b) => comparer.Compare( (Priority)a.EventListenerAttribute.Priority, (Priority)b.EventListenerAttribute.Priority) ); foreach (var group in eventSubscriptions.GroupBy(e => e.Scope)) { // Creates a new scope for the event. This is needed for scoped services so they share the same service instance // on each events. AutofacWebRequest makes it emulate a request for proper scopes. This tag is hardcoded by AutoFac. // Without this tag, services with the "Scope" lifetime will cause "DependencyResolutionException: // No scope with a Tag matching 'AutofacWebRequest' (...)". // // If you are here because of the following error: "System.ObjectDisposedException: Instances cannot // be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) // has already been disposed." It means you injected a service to an IEventHandler // that used the service *after* the event has finished (e.g. in a Task or by storing it somewhere). await using var newScope = group.Key.BeginLifetimeScopeEx("AutofacWebRequest"); foreach (var subscription in group) { var cancellableEvent = @event as ICancellableEvent; if (cancellableEvent != null && cancellableEvent.IsCancelled && !subscription.EventListenerAttribute.IgnoreCancelled) { continue; } var wasCancelled = false; if (cancellableEvent != null) { wasCancelled = cancellableEvent.IsCancelled; } var serviceProvider = newScope.Resolve <IServiceProvider>(); try { await subscription.Callback.Invoke(serviceProvider, sender, @event); // Ensure monitor event listeners can't cancel or uncancel events if (cancellableEvent != null && subscription.EventListenerAttribute.Priority == EventListenerPriority.Monitor) { if (cancellableEvent.IsCancelled != wasCancelled) { cancellableEvent.IsCancelled = wasCancelled; m_Logger.LogWarning( $"{((IOpenModComponent)@subscription.Owner.Target).OpenModComponentId} changed {@eventName} cancellation status with Monitor priority which is not permitted."); } } } catch (Exception ex) { m_Logger.LogError(ex, $"Exception occured during event {@eventName}"); } } } m_Logger.LogTrace($"{eventName}: Finished."); } callback?.Invoke(@event); }