mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Core/UI - Move from Ninject to DryIoc (#754)
This commit is contained in:
1 parent
166cb888c1
commit
b7e723b7e9
121 files changed
+1175
-980
No files matched your search
@@ -35,15 +35,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DryIoc.dll" Version="5.3.1" />
|
||||
<PackageReference Include="EmbedIO" Version="3.5.0" />
|
||||
<PackageReference Include="HidSharp" Version="2.1.0" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.12" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Ninject" Version="3.3.6" />
|
||||
<PackageReference Include="Ninject.Extensions.ChildKernel" Version="3.3.0" />
|
||||
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" />
|
||||
<PackageReference Include="RGB.NET.Core" Version="1.0.0" />
|
||||
<PackageReference Include="RGB.NET.Layout" Version="1.0.0" />
|
||||
<PackageReference Include="RGB.NET.Presets" Version="1.0.0" />
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.DryIoc.Factories;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage;
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using DryIoc;
|
||||
|
||||
namespace Artemis.Core.DryIoc;
|
||||
|
||||
/// <summary>
|
||||
/// The main <see cref="IModule" /> of the Artemis Core that binds all services
|
||||
/// </summary>
|
||||
public class CoreModule : IModule
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Load(IRegistrator builder)
|
||||
{
|
||||
Assembly coreAssembly = typeof(IArtemisService).Assembly;
|
||||
Assembly storageAssembly = typeof(IRepository).Assembly;
|
||||
|
||||
// Bind all services as singletons
|
||||
builder.RegisterMany(new[] {coreAssembly}, type => type.IsAssignableTo<IArtemisService>(), Reuse.Singleton);
|
||||
builder.RegisterMany(new[] {coreAssembly}, type => type.IsAssignableTo<IProtectedArtemisService>(), Reuse.Singleton, setup: Setup.With(condition: HasAccessToProtectedService));
|
||||
|
||||
// Bind storage
|
||||
builder.RegisterDelegate(() => StorageManager.CreateRepository(Constants.DataFolder), Reuse.Singleton);
|
||||
builder.Register<StorageMigrationService>(Reuse.Singleton);
|
||||
builder.RegisterMany(new[] {storageAssembly}, type => type.IsAssignableTo<IRepository>(), Reuse.Singleton);
|
||||
|
||||
// Bind migrations
|
||||
builder.RegisterMany(new[] { storageAssembly }, type => type.IsAssignableTo<IStorageMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
||||
|
||||
builder.Register<IPluginSettingsFactory, PluginSettingsFactory>(Reuse.Singleton);
|
||||
builder.Register(made: Made.Of(_ => ServiceInfo.Of<IPluginSettingsFactory>(), factory => factory.CreatePluginSettings(Arg.Index<Type>(0)), r => r.Parent.ImplementationType));
|
||||
builder.Register<ILoggerFactory, LoggerFactory>(Reuse.Singleton);
|
||||
builder.Register(made: Made.Of(_ => ServiceInfo.Of<ILoggerFactory>(), f => f.CreateLogger(Arg.Index<Type>(0)), r => r.Parent.ImplementationType));
|
||||
}
|
||||
|
||||
private bool HasAccessToProtectedService(Request request)
|
||||
{
|
||||
// Plugin assembly locations may not be set for some reason, that case it's also not allowed >:(
|
||||
return request.Parent.ImplementationType != null &&
|
||||
!string.IsNullOrWhiteSpace(request.Parent.ImplementationType.Assembly.Location) &&
|
||||
!request.Parent.ImplementationType.Assembly.Location.StartsWith(Constants.PluginsFolder);
|
||||
}
|
||||
}
|
||||
+12
-10
@@ -1,17 +1,16 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Ninject.Activation;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Artemis.Core.Ninject;
|
||||
namespace Artemis.Core.DryIoc.Factories;
|
||||
|
||||
internal class LoggerProvider : Provider<ILogger>
|
||||
internal class LoggerFactory : ILoggerFactory
|
||||
{
|
||||
internal static readonly LoggingLevelSwitch LoggingLevelSwitch = new(LogEventLevel.Verbose);
|
||||
|
||||
private static readonly ILogger Logger = new LoggerConfiguration()
|
||||
internal static readonly ILogger Logger = new LoggerConfiguration()
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.File(Path.Combine(Constants.LogsFolder, "Artemis log-.log"),
|
||||
rollingInterval: RollingInterval.Day,
|
||||
@@ -24,12 +23,10 @@ internal class LoggerProvider : Provider<ILogger>
|
||||
.MinimumLevel.ControlledBy(LoggingLevelSwitch)
|
||||
.CreateLogger();
|
||||
|
||||
protected override ILogger CreateInstance(IContext context)
|
||||
/// <inheritdoc />
|
||||
public ILogger CreateLogger(Type type)
|
||||
{
|
||||
Type? requestingType = context.Request.ParentContext?.Plan?.Type;
|
||||
if (requestingType != null)
|
||||
return Logger.ForContext(requestingType);
|
||||
return Logger;
|
||||
return Logger.ForContext(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,4 +37,9 @@ internal class ArtemisSink : ILogEventSink
|
||||
{
|
||||
LogStore.Emit(logEvent);
|
||||
}
|
||||
}
|
||||
|
||||
internal interface ILoggerFactory
|
||||
{
|
||||
ILogger CreateLogger(Type type);
|
||||
}
|
||||
+12
-16
@@ -1,35 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using Ninject.Activation;
|
||||
|
||||
namespace Artemis.Core.Ninject;
|
||||
namespace Artemis.Core.DryIoc.Factories;
|
||||
|
||||
// TODO: Investigate if this can't just be set as a constant on the plugin child kernel
|
||||
internal class PluginSettingsProvider : Provider<PluginSettings>
|
||||
internal class PluginSettingsFactory : IPluginSettingsFactory
|
||||
{
|
||||
private static readonly List<PluginSettings> PluginSettings = new();
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly IPluginRepository _pluginRepository;
|
||||
|
||||
public PluginSettingsProvider(IPluginRepository pluginRepository, IPluginManagementService pluginManagementService)
|
||||
public PluginSettingsFactory(IPluginRepository pluginRepository, IPluginManagementService pluginManagementService)
|
||||
{
|
||||
_pluginRepository = pluginRepository;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
}
|
||||
|
||||
protected override PluginSettings CreateInstance(IContext context)
|
||||
public PluginSettings CreatePluginSettings(Type type)
|
||||
{
|
||||
IRequest parentRequest = context.Request.ParentRequest;
|
||||
if (parentRequest == null)
|
||||
throw new ArtemisCoreException("PluginSettings couldn't be injected, failed to get the injection parent request");
|
||||
|
||||
// First try by PluginInfo parameter
|
||||
Plugin? plugin = parentRequest.Parameters.FirstOrDefault(p => p.Name == "Plugin")?.GetValue(context, null) as Plugin;
|
||||
// Fall back to assembly based detection
|
||||
if (plugin == null)
|
||||
plugin = _pluginManagementService.GetPluginByAssembly(parentRequest.Service.Assembly);
|
||||
Plugin? plugin = _pluginManagementService.GetPluginByAssembly(type.Assembly);
|
||||
|
||||
if (plugin == null)
|
||||
throw new ArtemisCoreException("PluginSettings can only be injected with the PluginInfo parameter provided " +
|
||||
@@ -46,4 +37,9 @@ internal class PluginSettingsProvider : Provider<PluginSettings>
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal interface IPluginSettingsFactory
|
||||
{
|
||||
PluginSettings CreatePluginSettings(Type type);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using DryIoc;
|
||||
|
||||
namespace Artemis.Core.DryIoc;
|
||||
|
||||
/**
|
||||
* Represents a service module.
|
||||
*/
|
||||
public interface IModule
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the services provided by the module.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder to register the services with.</param>
|
||||
void Load(IRegistrator builder);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Services;
|
||||
using DryIoc;
|
||||
|
||||
namespace Artemis.Core.DryIoc;
|
||||
|
||||
internal class PluginModule : IModule
|
||||
{
|
||||
public PluginModule(Plugin plugin)
|
||||
{
|
||||
Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin));
|
||||
}
|
||||
|
||||
public Plugin Plugin { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Load(IRegistrator builder)
|
||||
{
|
||||
builder.RegisterInstance(Plugin, setup: Setup.With(preventDisposal: true));
|
||||
|
||||
// Bind plugin service interfaces, DryIoc expects at least one match when calling RegisterMany so ensure there is something to register first
|
||||
if (Plugin.Assembly != null && Plugin.Assembly.GetTypes().Any(t => t.IsAssignableTo<IPluginService>()))
|
||||
builder.RegisterMany(new[] {Plugin.Assembly}, type => type.IsAssignableTo<IPluginService>(), Reuse.Singleton, ifAlreadyRegistered: IfAlreadyRegistered.Keep);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,11 @@ namespace Artemis.Core;
|
||||
/// </summary>
|
||||
public class ProfileCategory : CorePropertyChanged, IStorageModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an empty profile category.
|
||||
/// </summary>
|
||||
public static readonly ProfileCategory Empty = new("Empty", -1);
|
||||
|
||||
private readonly List<ProfileConfiguration> _profileConfigurations = new();
|
||||
private bool _isCollapsed;
|
||||
private bool _isSuspended;
|
||||
|
||||
@@ -11,6 +11,11 @@ namespace Artemis.Core;
|
||||
/// </summary>
|
||||
public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an empty profile.
|
||||
/// </summary>
|
||||
public static readonly ProfileConfiguration Empty = new(ProfileCategory.Empty, "Empty", "Empty");
|
||||
|
||||
private ActivationBehaviour _activationBehaviour;
|
||||
private bool _activationConditionMet;
|
||||
private ProfileCategory _category;
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage;
|
||||
using Artemis.Storage.Migrations.Interfaces;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using LiteDB;
|
||||
using Ninject.Activation;
|
||||
using Ninject.Extensions.Conventions;
|
||||
using Ninject.Modules;
|
||||
using Ninject.Planning.Bindings.Resolvers;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Core.Ninject;
|
||||
|
||||
/// <summary>
|
||||
/// The main <see cref="NinjectModule" /> of the Artemis Core that binds all services
|
||||
/// </summary>
|
||||
public class CoreModule : NinjectModule
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Load()
|
||||
{
|
||||
if (Kernel == null)
|
||||
throw new ArtemisCoreException("Failed to bind Ninject Core module, kernel is null.");
|
||||
|
||||
Kernel.Components.Remove<IMissingBindingResolver, SelfBindingResolver>();
|
||||
|
||||
// Bind all services as singletons
|
||||
Kernel.Bind(x =>
|
||||
{
|
||||
x.FromThisAssembly()
|
||||
.IncludingNonPublicTypes()
|
||||
.SelectAllClasses()
|
||||
.InheritedFrom<IArtemisService>()
|
||||
.BindAllInterfaces()
|
||||
.Configure(c => c.InSingletonScope());
|
||||
});
|
||||
|
||||
// Bind all protected services as singletons
|
||||
Kernel.Bind(x =>
|
||||
{
|
||||
x.FromThisAssembly()
|
||||
.IncludingNonPublicTypes()
|
||||
.SelectAllClasses()
|
||||
.InheritedFrom<IProtectedArtemisService>()
|
||||
.BindAllInterfaces()
|
||||
.Configure(c => c.When(HasAccessToProtectedService).InSingletonScope());
|
||||
});
|
||||
|
||||
Kernel.Bind<LiteRepository>().ToMethod(_ => StorageManager.CreateRepository(Constants.DataFolder)).InSingletonScope();
|
||||
Kernel.Bind<StorageMigrationService>().ToSelf().InSingletonScope();
|
||||
|
||||
// Bind all migrations as singletons
|
||||
Kernel.Bind(x =>
|
||||
{
|
||||
x.FromAssemblyContaining<IStorageMigration>()
|
||||
.IncludingNonPublicTypes()
|
||||
.SelectAllClasses()
|
||||
.InheritedFrom<IStorageMigration>()
|
||||
.BindAllInterfaces()
|
||||
.Configure(c => c.InSingletonScope());
|
||||
});
|
||||
|
||||
// Bind all repositories as singletons
|
||||
Kernel.Bind(x =>
|
||||
{
|
||||
x.FromAssemblyContaining<IRepository>()
|
||||
.IncludingNonPublicTypes()
|
||||
.SelectAllClasses()
|
||||
.InheritedFrom<IRepository>()
|
||||
.BindAllInterfaces()
|
||||
.Configure(c => c.InSingletonScope());
|
||||
});
|
||||
|
||||
Kernel.Bind<PluginSettings>().ToProvider<PluginSettingsProvider>();
|
||||
Kernel.Bind<ILogger>().ToProvider<LoggerProvider>();
|
||||
Kernel.Bind<LoggerProvider>().ToSelf();
|
||||
}
|
||||
|
||||
private bool HasAccessToProtectedService(IRequest r)
|
||||
{
|
||||
return r.ParentRequest != null && !r.ParentRequest.Service.Assembly.Location.StartsWith(Constants.PluginsFolder);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using Artemis.Core.Services;
|
||||
using Ninject.Extensions.Conventions;
|
||||
using Ninject.Modules;
|
||||
using Ninject.Planning.Bindings.Resolvers;
|
||||
|
||||
namespace Artemis.Core.Ninject;
|
||||
|
||||
internal class PluginModule : NinjectModule
|
||||
{
|
||||
public PluginModule(Plugin plugin)
|
||||
{
|
||||
Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin));
|
||||
}
|
||||
|
||||
public Plugin Plugin { get; }
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
if (Kernel == null)
|
||||
throw new ArtemisCoreException("Failed to bind plugin child module, kernel is null.");
|
||||
|
||||
Kernel.Components.Remove<IMissingBindingResolver, SelfBindingResolver>();
|
||||
|
||||
Kernel.Bind<Plugin>().ToConstant(Plugin).InTransientScope();
|
||||
|
||||
// Bind plugin service interfaces
|
||||
Kernel.Bind(x =>
|
||||
{
|
||||
x.From(Plugin.Assembly)
|
||||
.IncludingNonPublicTypes()
|
||||
.SelectAllClasses()
|
||||
.InheritedFrom<IPluginService>()
|
||||
.BindAllInterfaces()
|
||||
.Configure(c => c.InSingletonScope());
|
||||
});
|
||||
|
||||
// Plugin developers may not use an interface so bind the plugin services to themselves
|
||||
// Sadly if they do both, the kernel will treat the interface and the base type as two different singletons
|
||||
// perhaps we can avoid that, but I'm not sure how
|
||||
Kernel.Bind(x =>
|
||||
{
|
||||
x.From(Plugin.Assembly)
|
||||
.IncludingNonPublicTypes()
|
||||
.SelectAllClasses()
|
||||
.InheritedFrom<IPluginService>()
|
||||
.BindToSelf()
|
||||
.Configure(c => c.InSingletonScope());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Artemis.Core.Services;
|
||||
using Ninject;
|
||||
using Ninject.Activation;
|
||||
|
||||
namespace Artemis.Core.Ninject;
|
||||
|
||||
internal class SettingsServiceProvider : Provider<ISettingsService>
|
||||
{
|
||||
private readonly SettingsService _instance;
|
||||
|
||||
public SettingsServiceProvider(IKernel kernel)
|
||||
{
|
||||
// This is not lazy, but the core is always going to be using this anyway
|
||||
_instance = kernel.Get<SettingsService>();
|
||||
}
|
||||
|
||||
protected override ISettingsService CreateInstance(IContext context)
|
||||
{
|
||||
IRequest parentRequest = context.Request.ParentRequest;
|
||||
if (parentRequest == null || typeof(PluginFeature).IsAssignableFrom(parentRequest.Service))
|
||||
throw new ArtemisPluginException($"SettingsService can not be injected into a plugin. Inject {nameof(PluginSettings)} instead.");
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Ninject;
|
||||
using RGB.NET.Core;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Core.DeviceProviders;
|
||||
|
||||
@@ -26,14 +24,7 @@ public abstract class DeviceProvider : PluginFeature
|
||||
/// The RGB.NET device provider backing this Artemis device provider
|
||||
/// </summary>
|
||||
public IRGBDeviceProvider RgbDeviceProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Make internal while still injecting.
|
||||
/// A logger used by the device provider internally, ignore this
|
||||
/// </summary>
|
||||
[Inject]
|
||||
public ILogger? Logger { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A boolean indicating whether this device provider detects the physical layout of connected keyboards.
|
||||
/// <para>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Ninject;
|
||||
|
||||
namespace Artemis.Core.LayerBrushes;
|
||||
|
||||
@@ -63,7 +62,7 @@ public class LayerBrushDescriptor
|
||||
if (layer == null)
|
||||
throw new ArgumentNullException(nameof(layer));
|
||||
|
||||
BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Kernel!.Get(LayerBrushType);
|
||||
BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Resolve(LayerBrushType);
|
||||
brush.Layer = layer;
|
||||
brush.Descriptor = this;
|
||||
brush.LayerBrushEntity = entity ?? new LayerBrushEntity {ProviderId = Provider.Id, BrushType = LayerBrushType.FullName};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Artemis.Core.LayerEffects.Placeholder;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Ninject;
|
||||
|
||||
namespace Artemis.Core.LayerEffects;
|
||||
|
||||
@@ -80,7 +79,7 @@ public class LayerEffectDescriptor
|
||||
if (LayerEffectType == null)
|
||||
throw new ArtemisCoreException("Cannot create an instance of a layer effect because this descriptor is not a placeholder but is still missing its LayerEffectType");
|
||||
|
||||
BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Kernel!.Get(LayerEffectType);
|
||||
BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Resolve(LayerEffectType);
|
||||
effect.ProfileElement = renderElement;
|
||||
effect.Descriptor = this;
|
||||
if (entity != null)
|
||||
|
||||
@@ -7,8 +7,8 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using Artemis.Core.DeviceProviders;
|
||||
using Artemis.Storage.Entities.Plugins;
|
||||
using DryIoc;
|
||||
using McMaster.NETCore.Plugins;
|
||||
using Ninject;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
@@ -88,9 +88,9 @@ public class Plugin : CorePropertyChanged, IDisposable
|
||||
public PluginBootstrapper? Bootstrapper { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Ninject kernel of the plugin
|
||||
/// Gets the IOC container of the plugin, only use this for advanced IOC operations, otherwise see <see cref="Resolve"/> and <see cref="Resolve{T}"/>
|
||||
/// </summary>
|
||||
public IKernel? Kernel { get; internal set; }
|
||||
public IContainer? Container { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The PluginLoader backing this plugin
|
||||
@@ -165,16 +165,66 @@ public class Plugin : CorePropertyChanged, IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of the specified service using the plugins dependency injection container.
|
||||
/// <para>Note: To use parameters reference Ninject and use <see cref="Kernel" /> directly.</para>
|
||||
/// Gets an instance of the specified service using the plugins dependency injection container.
|
||||
/// </summary>
|
||||
/// <param name="arguments">Arguments to supply to the service.</param>
|
||||
/// <typeparam name="T">The service to resolve.</typeparam>
|
||||
/// <returns>An instance of the service.</returns>
|
||||
public T Get<T>()
|
||||
/// <seealso cref="Resolve"/>
|
||||
public T Resolve<T>(params object?[] arguments)
|
||||
{
|
||||
if (Kernel == null)
|
||||
throw new ArtemisPluginException("Cannot use Get<T> before the plugin finished loading");
|
||||
return Kernel.Get<T>();
|
||||
if (Container == null)
|
||||
throw new ArtemisPluginException("Cannot use Resolve<T> before the plugin finished loading");
|
||||
return Container.Resolve<T>(args: arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of the specified service using the plugins dependency injection container.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of service to resolve.</param>
|
||||
/// <param name="arguments">Arguments to supply to the service.</param>
|
||||
/// <returns>An instance of the service.</returns>
|
||||
/// <seealso cref="Resolve{T}"/>
|
||||
public object Resolve(Type type, params object?[] arguments)
|
||||
{
|
||||
if (Container == null)
|
||||
throw new ArtemisPluginException("Cannot use Resolve before the plugin finished loading");
|
||||
return Container.Resolve(type, args: arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers service of <typeparamref name="TService" /> type implemented by <typeparamref name="TImplementation" /> type.
|
||||
/// </summary>
|
||||
/// <param name="scope">The scope in which the service should live, if you are not sure leave it on singleton.</param>
|
||||
/// <typeparam name="TService">The service to register.</typeparam>
|
||||
/// <typeparam name="TImplementation">The implementation of the service to register.</typeparam>
|
||||
public void Register<TService, TImplementation>(PluginServiceScope scope = PluginServiceScope.Singleton) where TImplementation : TService
|
||||
{
|
||||
IReuse reuse = scope switch
|
||||
{
|
||||
PluginServiceScope.Transient => Reuse.Transient,
|
||||
PluginServiceScope.Singleton => Reuse.Singleton,
|
||||
PluginServiceScope.Scoped => Reuse.Scoped,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(scope), scope, null)
|
||||
};
|
||||
Container.Register<TService, TImplementation>(reuse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers implementation type <typeparamref name="TImplementation" /> with itself as service type.
|
||||
/// </summary>
|
||||
/// <param name="scope">The scope in which the service should live, if you are not sure leave it on singleton.</param>
|
||||
/// <typeparam name="TImplementation">The implementation of the service to register.</typeparam>
|
||||
public void Register<TImplementation>(PluginServiceScope scope = PluginServiceScope.Singleton)
|
||||
{
|
||||
IReuse reuse = scope switch
|
||||
{
|
||||
PluginServiceScope.Transient => Reuse.Transient,
|
||||
PluginServiceScope.Singleton => Reuse.Singleton,
|
||||
PluginServiceScope.Scoped => Reuse.Scoped,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(scope), scope, null)
|
||||
};
|
||||
Container.Register<TImplementation>(reuse);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -218,7 +268,7 @@ public class Plugin : CorePropertyChanged, IDisposable
|
||||
feature.Instance?.Dispose();
|
||||
SetEnabled(false);
|
||||
|
||||
Kernel?.Dispose();
|
||||
Container?.Dispose();
|
||||
PluginLoader?.Dispose();
|
||||
|
||||
GC.Collect();
|
||||
@@ -340,4 +390,26 @@ public class Plugin : CorePropertyChanged, IDisposable
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a scope in which a plugin service is injected by the IOC container.
|
||||
/// </summary>
|
||||
public enum PluginServiceScope
|
||||
{
|
||||
/// <summary>
|
||||
/// Services in this scope are never reused, a new instance is injected each time.
|
||||
/// </summary>
|
||||
Transient,
|
||||
|
||||
/// <summary>
|
||||
/// Services in this scope are reused for as long as the plugin lives, the same instance is injected each time.
|
||||
/// </summary>
|
||||
Singleton,
|
||||
|
||||
/// <summary>
|
||||
/// Services in this scope are reused within a container scope, this is an advanced setting you shouldn't need.
|
||||
/// <para>To learn more see <a href="https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/ReuseAndScopes.md#reusescoped">the DryIoc docs</a>.</para>
|
||||
/// </summary>
|
||||
Scoped
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.DeviceProviders;
|
||||
using Artemis.Core.LayerBrushes;
|
||||
using Artemis.Core.LayerEffects;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Storage.Entities.Plugins;
|
||||
using Humanizer;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Artemis.Core.DryIoc.Factories;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Ninject;
|
||||
using Serilog;
|
||||
|
||||
namespace Artemis.Core;
|
||||
@@ -11,7 +10,7 @@ namespace Artemis.Core;
|
||||
/// <summary>
|
||||
/// Represents a registration for a timed plugin update
|
||||
/// </summary>
|
||||
public class TimedUpdateRegistration : IDisposable
|
||||
public sealed class TimedUpdateRegistration : IDisposable
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private readonly ILogger _logger;
|
||||
@@ -21,9 +20,7 @@ public class TimedUpdateRegistration : IDisposable
|
||||
|
||||
internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Action<double> action, string? name)
|
||||
{
|
||||
if (CoreService.Kernel == null)
|
||||
throw new ArtemisCoreException("Cannot create a TimedUpdateRegistration before initializing the Core");
|
||||
_logger = CoreService.Kernel.Get<ILogger>();
|
||||
_logger = LoggerFactory.Logger.ForContext<TimedUpdateRegistration>();
|
||||
|
||||
Feature = feature;
|
||||
Interval = interval;
|
||||
@@ -38,9 +35,7 @@ public class TimedUpdateRegistration : IDisposable
|
||||
|
||||
internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Func<double, Task> asyncAction, string? name)
|
||||
{
|
||||
if (CoreService.Kernel == null)
|
||||
throw new ArtemisCoreException("Cannot create a TimedUpdateRegistration before initializing the Core");
|
||||
_logger = CoreService.Kernel.Get<ILogger>();
|
||||
_logger = LoggerFactory.Logger.ForContext<TimedUpdateRegistration>();
|
||||
|
||||
Feature = feature;
|
||||
Interval = interval;
|
||||
@@ -125,33 +120,13 @@ public class TimedUpdateRegistration : IDisposable
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override string ToString()
|
||||
public override string ToString()
|
||||
{
|
||||
if (Interval.TotalSeconds >= 1)
|
||||
return $"{Name} ({Interval.TotalSeconds} sec)";
|
||||
return $"{Name} ({Interval.TotalMilliseconds} ms)";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">
|
||||
/// <see langword="true" /> to release both managed and unmanaged resources;
|
||||
/// <see langword="false" /> to release only unmanaged resources.
|
||||
/// </param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Stop();
|
||||
|
||||
Feature.Enabled -= FeatureOnEnabled;
|
||||
Feature.Disabled -= FeatureOnDisabled;
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void TimerOnElapsed(object? sender, ElapsedEventArgs e)
|
||||
{
|
||||
if (!Feature.IsEnabled)
|
||||
@@ -204,9 +179,12 @@ public class TimedUpdateRegistration : IDisposable
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
Feature.Profiler.ClearMeasurements(ToString());
|
||||
Stop();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
Feature.Enabled -= FeatureOnEnabled;
|
||||
Feature.Disabled -= FeatureOnDisabled;
|
||||
|
||||
_disposed = true;
|
||||
Feature.Profiler.ClearMeasurements(ToString());
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,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 :(");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Artemis.Storage.Entities.Profile.Nodes;
|
||||
using Castle.Core.Internal;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Events;
|
||||
using DryIoc;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
@@ -103,6 +104,8 @@ public abstract class Node : BreakableModel, INode
|
||||
/// <inheritdoc />
|
||||
public override string BrokenDisplayName => Name;
|
||||
|
||||
internal IContainer Container { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construtors
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Artemis.Core;
|
||||
using Ninject;
|
||||
using Ninject.Parameters;
|
||||
using DryIoc;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a kind of node inside a <see cref="NodeScript" /> containing storage value of type
|
||||
@@ -22,26 +19,13 @@ public abstract class Node<TStorage, TViewModel> : Node<TStorage>, ICustomViewMo
|
||||
{
|
||||
}
|
||||
|
||||
[Inject]
|
||||
internal IKernel Kernel { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a view model is required
|
||||
/// </summary>
|
||||
/// <param name="nodeScript"></param>
|
||||
public virtual TViewModel GetViewModel(NodeScript nodeScript)
|
||||
{
|
||||
// Limit to one constructor, there's no need to have more and it complicates things anyway
|
||||
ConstructorInfo[] constructors = typeof(TViewModel).GetConstructors();
|
||||
if (constructors.Length != 1)
|
||||
throw new ArtemisCoreException("Node VMs 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 => GetType().IsAssignableFrom(p.ParameterType));
|
||||
|
||||
if (configurationParameter?.Name == null)
|
||||
throw new ArtemisCoreException($"Couldn't find a valid constructor argument on {typeof(TViewModel).Name} with type {GetType().Name}");
|
||||
return Kernel.Get<TViewModel>(new ConstructorArgument(configurationParameter.Name, this), new ConstructorArgument("script", nodeScript));
|
||||
return Container.Resolve<TViewModel>(args: new object[] {this, nodeScript});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in new issue
Block a user