Core/UI - Move from Ninject to DryIoc (#754)

This commit is contained in:
RobertBeekman authored and GitHub committed 2023-01-30 21:00:10 +01:00
1 parent 166cb888c1
commit b7e723b7e9
121 files changed
+1175 -980

No files matched your search

+7 -15
View File
@@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Artemis.Core.Ninject;
using Artemis.Core.DryIoc.Factories;
using Artemis.Core.ScriptingProviders;
using Artemis.Storage;
using DryIoc;
using HidSharp;
using Ninject;
using RGB.NET.Core;
using Serilog;
using Serilog.Events;
@@ -20,7 +20,6 @@ namespace Artemis.Core.Services;
/// </summary>
internal class CoreService : ICoreService
{
internal static IKernel? Kernel;
private readonly Stopwatch _frameStopWatch;
private readonly ILogger _logger;
private readonly PluginSetting<LogEventLevel> _loggingLevel;
@@ -36,7 +35,7 @@ internal class CoreService : ICoreService
private DateTime _lastFrameRateSample;
// ReSharper disable UnusedParameter.Local
public CoreService(IKernel kernel,
public CoreService(IContainer container,
ILogger logger,
StorageMigrationService _1, // injected to ensure migration runs early
ISettingsService settingsService,
@@ -47,8 +46,7 @@ internal class CoreService : ICoreService
IScriptingService scriptingService,
IProcessMonitorService _2)
{
Kernel = kernel;
Constants.CorePlugin.Kernel = kernel;
Constants.CorePlugin.Container = container;
_logger = logger;
_pluginManagementService = pluginManagementService;
@@ -85,19 +83,19 @@ internal class CoreService : ICoreService
if (parts.Length == 2 && Enum.TryParse(typeof(LogEventLevel), parts[1], true, out object? logLevelArgument))
{
_logger.Information("Setting logging level to {loggingLevel} from startup argument", (LogEventLevel) logLevelArgument!);
LoggerProvider.LoggingLevelSwitch.MinimumLevel = (LogEventLevel) logLevelArgument;
LoggerFactory.LoggingLevelSwitch.MinimumLevel = (LogEventLevel) logLevelArgument;
}
else
{
_logger.Warning("Failed to set log level from startup argument {argument}", argument);
_logger.Information("Setting logging level to {loggingLevel}", _loggingLevel.Value);
LoggerProvider.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value;
LoggerFactory.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value;
}
}
else
{
_logger.Information("Setting logging level to {loggingLevel}", _loggingLevel.Value);
LoggerProvider.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value;
LoggerFactory.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value;
}
}
@@ -195,12 +193,6 @@ internal class CoreService : ICoreService
public bool ProfileRenderingDisabled { get; set; }
public bool IsElevated { get; set; }
public void Dispose()
{
// Dispose services
_pluginManagementService.Dispose();
}
public bool IsInitialized { get; set; }
public void Initialize()
@@ -5,7 +5,7 @@ namespace Artemis.Core.Services;
/// <summary>
/// A service that initializes the Core and manages the render loop
/// </summary>
public interface ICoreService : IArtemisService, IDisposable
public interface ICoreService : IArtemisService
{
/// <summary>
/// Gets whether the or not the core has been initialized
+10 -8
View File
@@ -5,8 +5,8 @@ using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using Artemis.Storage.Entities.Profile.Nodes;
using DryIoc;
using Newtonsoft.Json;
using Ninject;
using SkiaSharp;
namespace Artemis.Core.Services;
@@ -15,17 +15,17 @@ internal class NodeService : INodeService
{
#region Constants
private static readonly Type TYPE_NODE = typeof(INode);
private static readonly Type TypeNode = typeof(INode);
#endregion
private readonly IKernel _kernel;
private readonly IContainer _container;
#region Constructors
public NodeService(IKernel kernel)
public NodeService(IContainer container)
{
_kernel = kernel;
_container = container;
}
#endregion
@@ -69,7 +69,7 @@ internal class NodeService : INodeService
if (plugin == null) throw new ArgumentNullException(nameof(plugin));
if (nodeType == null) throw new ArgumentNullException(nameof(nodeType));
if (!TYPE_NODE.IsAssignableFrom(nodeType)) throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType));
if (!TypeNode.IsAssignableFrom(nodeType)) throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType));
NodeAttribute? nodeAttribute = nodeType.GetCustomAttribute<NodeAttribute>();
string name = nodeAttribute?.Name ?? nodeType.Name;
@@ -106,8 +106,10 @@ internal class NodeService : INodeService
private INode CreateNode(INodeScript script, NodeEntity? entity, Type nodeType)
{
INode node = _kernel.Get(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode");
INode node = _container.Resolve(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode");
if (node is Node concreteNode)
concreteNode.Container = _container;
if (entity != null)
{
node.X = entity.X;
@@ -5,19 +5,15 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading.Tasks;
using Artemis.Core.DeviceProviders;
using Artemis.Core.Ninject;
using Artemis.Core.DryIoc;
using Artemis.Storage.Entities.General;
using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Entities.Surface;
using Artemis.Storage.Repositories.Interfaces;
using DryIoc;
using McMaster.NETCore.Plugins;
using Ninject;
using Ninject.Extensions.ChildKernel;
using Ninject.Parameters;
using Ninject.Planning.Bindings.Resolvers;
using RGB.NET.Core;
using Serilog;
@@ -29,7 +25,7 @@ namespace Artemis.Core.Services;
internal class PluginManagementService : IPluginManagementService
{
private readonly IDeviceRepository _deviceRepository;
private readonly IKernel _kernel;
private readonly IContainer _container;
private readonly ILogger _logger;
private readonly IPluginRepository _pluginRepository;
private readonly List<Plugin> _plugins;
@@ -37,9 +33,9 @@ internal class PluginManagementService : IPluginManagementService
private bool _disposed;
private bool _isElevated;
public PluginManagementService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository, IDeviceRepository deviceRepository, IQueuedActionRepository queuedActionRepository)
public PluginManagementService(IContainer container, ILogger logger, IPluginRepository pluginRepository, IDeviceRepository deviceRepository, IQueuedActionRepository queuedActionRepository)
{
_kernel = kernel;
_container = container;
_logger = logger;
_pluginRepository = pluginRepository;
_deviceRepository = deviceRepository;
@@ -198,6 +194,10 @@ internal class PluginManagementService : IPluginManagementService
public void Dispose()
{
// Disposal happens manually before container disposal but the container doesn't know that so a 2nd call will be made
if (_disposed)
return;
_disposed = true;
UnloadPlugins();
}
@@ -340,11 +340,11 @@ internal class PluginManagementService : IPluginManagementService
configure.IsUnloadable = true;
configure.LoadInMemory = true;
configure.PreferSharedTypes = true;
// Resolving failed, try a loaded assembly but ignoring the version
configure.DefaultContext.Resolving += (context, assemblyName) => context.Assemblies.FirstOrDefault(a => a.GetName().Name == assemblyName.Name);
});
try
{
plugin.Assembly = plugin.PluginLoader.LoadDefaultAssembly();
@@ -406,7 +406,7 @@ internal class PluginManagementService : IPluginManagementService
OnPluginLoaded(new PluginEventArgs(plugin));
return plugin;
}
public void EnablePlugin(Plugin plugin, bool saveState, bool ignorePluginLock)
{
if (!plugin.Info.IsCompatible)
@@ -431,10 +431,17 @@ internal class PluginManagementService : IPluginManagementService
if (!plugin.Info.ArePrerequisitesMet())
throw new ArtemisPluginPrerequisiteException(plugin.Info, "Cannot enable a plugin whose prerequisites aren't all met");
// Create the Ninject child kernel and load the module
plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin));
// The kernel used by Core is unforgiving about missing bindings, no need to be so hard on plugin devs
plugin.Kernel.Components.Add<IMissingBindingResolver, SelfBindingResolver>();
// Create a child container for the plugin, be a bit more forgiving about concrete types
plugin.Container = _container.CreateChild(newRules: _container.Rules.WithConcreteTypeDynamicRegistrations());
try
{
new PluginModule(plugin).Load(plugin.Container);
}
catch (Exception e)
{
_logger.Error(e, "Failed to register plugin services for plugin {plugin}, skipping enabling", plugin);
return;
}
OnPluginEnabling(new PluginEventArgs(plugin));
@@ -446,11 +453,8 @@ internal class PluginManagementService : IPluginManagementService
{
try
{
plugin.Kernel.Bind(featureInfo.FeatureType).ToSelf().InSingletonScope();
// Include Plugin as a parameter for the PluginSettingsProvider
IParameter[] parameters = {new Parameter("Plugin", plugin, false)};
PluginFeature instance = (PluginFeature) plugin.Kernel.Get(featureInfo.FeatureType, parameters);
plugin.Container.Register(featureInfo.FeatureType, reuse: Reuse.Singleton);
PluginFeature instance = (PluginFeature) plugin.Container.Resolve(featureInfo.FeatureType);
// Get the PluginFeature attribute which contains extra info on the feature
featureInfo.Instance = instance;
@@ -526,8 +530,8 @@ internal class PluginManagementService : IPluginManagementService
plugin.SetEnabled(false);
plugin.Kernel?.Dispose();
plugin.Kernel = null;
plugin.Container?.Dispose();
plugin.Container = null;
GC.Collect();
GC.WaitForPendingFinalizers();
+19 -13
View File
@@ -9,7 +9,7 @@ using Artemis.Core.Services.Models;
using Artemis.Core.SkiaSharp;
using Artemis.Storage.Entities.Surface;
using Artemis.Storage.Repositories.Interfaces;
using Ninject;
using DryIoc;
using RGB.NET.Core;
using Serilog;
@@ -20,31 +20,36 @@ namespace Artemis.Core.Services;
/// </summary>
internal class RgbService : IRgbService
{
private readonly IDeviceRepository _deviceRepository;
private readonly List<ArtemisDevice> _devices;
private readonly List<ArtemisDevice> _enabledDevices;
private readonly IKernel _kernel;
private readonly ILogger _logger;
private readonly IPluginManagementService _pluginManagementService;
private readonly IDeviceRepository _deviceRepository;
private readonly LazyEnumerable<IGraphicsContextProvider> _graphicsContextProviders;
private readonly PluginSetting<string> _preferredGraphicsContext;
private readonly PluginSetting<double> _renderScaleSetting;
private readonly ISettingsService _settingsService;
private readonly PluginSetting<int> _targetFrameRateSetting;
private readonly List<ArtemisDevice> _devices;
private readonly List<ArtemisDevice> _enabledDevices;
private readonly SKTextureBrush _textureBrush = new(null) {CalculationMode = RenderMode.Absolute};
private Dictionary<Led, ArtemisLed> _ledMap;
private ListLedGroup? _surfaceLedGroup;
private SKTexture? _texture;
public RgbService(ILogger logger, IKernel kernel, ISettingsService settingsService, IPluginManagementService pluginManagementService, IDeviceRepository deviceRepository)
public RgbService(ILogger logger,
ISettingsService settingsService,
IPluginManagementService pluginManagementService,
IDeviceRepository deviceRepository,
LazyEnumerable<IGraphicsContextProvider> graphicsContextProviders)
{
_logger = logger;
_kernel = kernel;
_settingsService = settingsService;
_pluginManagementService = pluginManagementService;
_deviceRepository = deviceRepository;
_graphicsContextProviders = graphicsContextProviders;
_targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30);
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25);
_preferredGraphicsContext = _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software");
_preferredGraphicsContext = settingsService.GetSetting("Core.PreferredGraphicsContext", "Software");
Surface = new RGBSurface();
Utilities.RenderScaleMultiplier = (int) (1 / _renderScaleSetting.Value);
@@ -226,7 +231,7 @@ internal class RgbService : IRgbService
{
_logger.Verbose("[AddDeviceProvider] Updating the LED group");
UpdateLedGroup();
_logger.Verbose("[AddDeviceProvider] Resuming rendering after adding {DeviceProvider}", deviceProvider.GetType().Name);
if (changedRenderPaused)
SetRenderPaused(false);
@@ -257,7 +262,7 @@ internal class RgbService : IRgbService
{
_logger.Verbose("[RemoveDeviceProvider] Updating the LED group");
UpdateLedGroup();
_logger.Verbose("[RemoveDeviceProvider] Resuming rendering after adding {DeviceProvider}", deviceProvider.GetType().Name);
if (changedRenderPaused)
SetRenderPaused(false);
@@ -372,7 +377,8 @@ internal class RgbService : IRgbService
return;
}
List<IGraphicsContextProvider> providers = _kernel.Get<List<IGraphicsContextProvider>>();
List<IGraphicsContextProvider> providers = _graphicsContextProviders.ToList();
if (!providers.Any())
{
_logger.Warning("No graphics context provider found, defaulting to software rendering");
+2 -29
View File
@@ -2,10 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using Artemis.Core.ScriptingProviders;
using Ninject;
using Ninject.Parameters;
namespace Artemis.Core.Services;
@@ -51,11 +48,7 @@ internal class ScriptingService : IScriptingService
if (provider == null)
throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId}).");
script = (GlobalScript) provider.Plugin.Kernel!.Get(
provider.GlobalScriptType,
CreateScriptConstructorArgument(provider.GlobalScriptType, scriptConfiguration)
);
script = (GlobalScript) provider.Plugin.Resolve(provider.GlobalScriptType, scriptConfiguration);
script.ScriptingProvider = provider;
script.ScriptingService = this;
scriptConfiguration.Script = script;
@@ -82,12 +75,7 @@ internal class ScriptingService : IScriptingService
if (provider == null)
throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId}).");
script = (ProfileScript) provider.Plugin.Kernel!.Get(
provider.ProfileScriptType,
CreateScriptConstructorArgument(provider.ProfileScriptType, profile),
CreateScriptConstructorArgument(provider.ProfileScriptType, scriptConfiguration)
);
script = (ProfileScript) provider.Plugin.Resolve(provider.ProfileScriptType, profile, scriptConfiguration);
script.ScriptingProvider = provider;
scriptConfiguration.Script = script;
provider.InternalScripts.Add(script);
@@ -113,21 +101,6 @@ internal class ScriptingService : IScriptingService
}
}
private ConstructorArgument CreateScriptConstructorArgument(Type scriptType, object value)
{
// Limit to one constructor, there's no need to have more and it complicates things anyway
ConstructorInfo[] constructors = scriptType.GetConstructors();
if (constructors.Length != 1)
throw new ArtemisCoreException("Scripts must have exactly one constructor");
// Find the ScriptConfiguration parameter, it is required by the base constructor so its there for sure
ParameterInfo? configurationParameter = constructors.First().GetParameters().FirstOrDefault(p => value.GetType().IsAssignableFrom(p.ParameterType));
if (configurationParameter?.Name == null)
throw new ArtemisCoreException($"Couldn't find a valid constructor argument on {scriptType.Name} with type {value.GetType().Name}");
return new ConstructorArgument(configurationParameter.Name, value);
}
private void InitializeProfileScripts(Profile profile)
{
// Initialize the scripts on the profile
@@ -1,6 +1,5 @@
using System;
using EmbedIO.WebApi;
using Ninject;
namespace Artemis.Core.Services;
@@ -8,7 +7,7 @@ internal class WebApiControllerRegistration<T> : WebApiControllerRegistration wh
{
public WebApiControllerRegistration(PluginFeature feature) : base(feature, typeof(T))
{
Factory = () => feature.Plugin.Kernel!.Get<T>();
Factory = () => feature.Plugin.Resolve<T>();
}
public Func<T> Factory { get; set; }
@@ -1,6 +1,6 @@
using System;
using EmbedIO;
using Ninject;
using DryIoc;
namespace Artemis.Core.Services;
@@ -27,7 +27,7 @@ internal class WebModuleRegistration
if (Create != null)
return Create();
if (WebModuleType != null)
return (IWebModule) Feature.Plugin.Kernel!.Get(WebModuleType);
return (IWebModule) Feature.Plugin.Resolve(WebModuleType);
throw new ArtemisCoreException("WebModuleRegistration doesn't have a create function nor a web module type :(");
}
}