diff --git a/src/Artemis.Core/DryIoc/ContainerExtensions.cs b/src/Artemis.Core/DryIoc/ContainerExtensions.cs new file mode 100644 index 000000000..4f418d453 --- /dev/null +++ b/src/Artemis.Core/DryIoc/ContainerExtensions.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; +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; + +/// +/// Provides an extension method to register services onto a DryIoc . +/// +public static class CoreContainerExtensions +{ + /// + /// Registers core services into the container. + /// + /// The builder building the current container + public static void RegisterCore(this IContainer container) + { + Assembly[] coreAssembly = {typeof(IArtemisService).Assembly}; + Assembly[] storageAssembly = {typeof(IRepository).Assembly}; + + // Bind all services as singletons + container.RegisterMany(coreAssembly, type => type.IsAssignableTo(), Reuse.Singleton); + container.RegisterMany(coreAssembly, type => type.IsAssignableTo(), Reuse.Singleton, setup: Setup.With(condition: HasAccessToProtectedService)); + + // Bind storage + container.RegisterDelegate(() => StorageManager.CreateRepository(Constants.DataFolder), Reuse.Singleton); + container.Register(Reuse.Singleton); + container.RegisterMany(storageAssembly, type => type.IsAssignableTo(), Reuse.Singleton); + + // Bind migrations + container.RegisterMany(storageAssembly, type => type.IsAssignableTo(), Reuse.Singleton, nonPublicServiceTypes: true); + + container.Register(Reuse.Singleton); + container.Register(made: Made.Of(_ => ServiceInfo.Of(), f => f.CreatePluginSettings(Arg.Index(0)), r => r.Parent.ImplementationType)); + container.Register(Reuse.Singleton); + container.Register(made: Made.Of(_ => ServiceInfo.Of(), f => f.CreateLogger(Arg.Index(0)), r => r.Parent.ImplementationType)); + } + + /// + /// Registers plugin services into the container, this is typically a child container. + /// + /// The builder building the current container + /// The plugin to register + public static void RegisterPlugin(this IContainer container, Plugin plugin) + { + container.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())) + container.RegisterMany(new[] {plugin.Assembly}, type => type.IsAssignableTo(), Reuse.Singleton, ifAlreadyRegistered: IfAlreadyRegistered.Keep); + } + + private static 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); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/DryIoc/CoreModule.cs b/src/Artemis.Core/DryIoc/CoreModule.cs deleted file mode 100644 index 0c41cb524..000000000 --- a/src/Artemis.Core/DryIoc/CoreModule.cs +++ /dev/null @@ -1,48 +0,0 @@ -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; - -/// -/// The main of the Artemis Core that binds all services -/// -public class CoreModule : IModule -{ - /// - 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(), Reuse.Singleton); - builder.RegisterMany(new[] {coreAssembly}, type => type.IsAssignableTo(), Reuse.Singleton, setup: Setup.With(condition: HasAccessToProtectedService)); - - // Bind storage - builder.RegisterDelegate(() => StorageManager.CreateRepository(Constants.DataFolder), Reuse.Singleton); - builder.Register(Reuse.Singleton); - builder.RegisterMany(new[] {storageAssembly}, type => type.IsAssignableTo(), Reuse.Singleton); - - // Bind migrations - builder.RegisterMany(new[] { storageAssembly }, type => type.IsAssignableTo(), Reuse.Singleton, nonPublicServiceTypes: true); - - builder.Register(Reuse.Singleton); - builder.Register(made: Made.Of(_ => ServiceInfo.Of(), factory => factory.CreatePluginSettings(Arg.Index(0)), r => r.Parent.ImplementationType)); - builder.Register(Reuse.Singleton); - builder.Register(made: Made.Of(_ => ServiceInfo.Of(), f => f.CreateLogger(Arg.Index(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); - } -} \ No newline at end of file diff --git a/src/Artemis.Core/DryIoc/IModule.cs b/src/Artemis.Core/DryIoc/IModule.cs deleted file mode 100644 index 08b3247a9..000000000 --- a/src/Artemis.Core/DryIoc/IModule.cs +++ /dev/null @@ -1,15 +0,0 @@ -using DryIoc; - -namespace Artemis.Core.DryIoc; - -/** - * Represents a service module. - */ -public interface IModule -{ - /// - /// Registers the services provided by the module. - /// - /// The builder to register the services with. - void Load(IRegistrator builder); -} \ No newline at end of file diff --git a/src/Artemis.Core/DryIoc/PluginModule.cs b/src/Artemis.Core/DryIoc/PluginModule.cs deleted file mode 100644 index d6ae8dd07..000000000 --- a/src/Artemis.Core/DryIoc/PluginModule.cs +++ /dev/null @@ -1,26 +0,0 @@ -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; } - - /// - 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())) - builder.RegisterMany(new[] {Plugin.Assembly}, type => type.IsAssignableTo(), Reuse.Singleton, ifAlreadyRegistered: IfAlreadyRegistered.Keep); - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 9565f6320..6de473234 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -435,7 +435,7 @@ internal class PluginManagementService : IPluginManagementService plugin.Container = _container.CreateChild(newRules: _container.Rules.WithConcreteTypeDynamicRegistrations()); try { - new PluginModule(plugin).Load(plugin.Container); + plugin.Container.RegisterPlugin(plugin); } catch (Exception e) { diff --git a/src/Artemis.UI.Linux/App.axaml.cs b/src/Artemis.UI.Linux/App.axaml.cs index f3fdb04cf..7040f8183 100644 --- a/src/Artemis.UI.Linux/App.axaml.cs +++ b/src/Artemis.UI.Linux/App.axaml.cs @@ -1,4 +1,5 @@ using Artemis.Core.Services; +using Artemis.UI.Linux.DryIoc; using Artemis.UI.Linux.Providers.Input; using Avalonia; using Avalonia.Controls; @@ -17,7 +18,7 @@ public class App : Application public override void Initialize() { - _container = ArtemisBootstrapper.Bootstrap(this); + _container = ArtemisBootstrapper.Bootstrap(this, c => c.RegisterProviders()); Program.CreateLogger(_container); RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); diff --git a/src/Artemis.UI.Linux/DryIoc/ContainerExtensions.cs b/src/Artemis.UI.Linux/DryIoc/ContainerExtensions.cs new file mode 100644 index 000000000..8647beea5 --- /dev/null +++ b/src/Artemis.UI.Linux/DryIoc/ContainerExtensions.cs @@ -0,0 +1,20 @@ +using Artemis.Core.Services; +using Artemis.UI.Linux.Providers.Input; +using DryIoc; + +namespace Artemis.UI.Linux.DryIoc; + +/// +/// Provides an extension method to register services onto a DryIoc . +/// +public static class UIContainerExtensions +{ + /// + /// Registers providers into the container. + /// + /// The builder building the current container + public static void RegisterProviders(this IContainer container) + { + container.Register(serviceKey: LinuxInputProvider.Id); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Linux/DryIoc/LinuxModule.cs b/src/Artemis.UI.Linux/DryIoc/LinuxModule.cs deleted file mode 100644 index 142e8b667..000000000 --- a/src/Artemis.UI.Linux/DryIoc/LinuxModule.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Artemis.Core.DryIoc; -using Artemis.Core.Services; -using Artemis.UI.Linux.Providers.Input; -using DryIoc; - -namespace Artemis.UI.Linux.DryIoc; - -public class LinuxModule : IModule -{ - - /// - public void Load(IRegistrator builder) - { - builder.Register(serviceKey: LinuxInputProvider.Id); - } - -} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs b/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs new file mode 100644 index 000000000..cb7baef36 --- /dev/null +++ b/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs @@ -0,0 +1,21 @@ +using System.Reflection; +using Artemis.UI.Shared.Services; +using DryIoc; + +namespace Artemis.UI.Shared.DryIoc; + +/// +/// Provides an extension method to register services onto a DryIoc . +/// +public static class UIContainerExtensions +{ + /// + /// Registers shared UI services into the container. + /// + /// The builder building the current container + public static void RegisterSharedUI(this IContainer container) + { + Assembly artemisShared = typeof(IArtemisSharedUIService).GetAssembly(); + container.RegisterMany(new[] { artemisShared }, type => type.IsAssignableTo(), Reuse.Singleton); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/DryIoc/SharedUIModule.cs b/src/Artemis.UI.Shared/DryIoc/SharedUIModule.cs deleted file mode 100644 index be6fcced3..000000000 --- a/src/Artemis.UI.Shared/DryIoc/SharedUIModule.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using Artemis.Core.DryIoc; -using Artemis.UI.Shared.Services; -using DryIoc; - -namespace Artemis.UI.Shared.DryIoc; - -/// -/// The main of the Artemis Shared UI toolkit that binds all services -/// -public class SharedUIModule : IModule -{ - /// - public void Load(IRegistrator builder) - { - Assembly artemisShared = typeof(IArtemisSharedUIService).GetAssembly(); - builder.RegisterMany(new[] { artemisShared }, type => type.IsAssignableTo(), Reuse.Singleton); - } -} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/App.axaml.cs b/src/Artemis.UI.Windows/App.axaml.cs index 38f0389a7..b2a8db3df 100644 --- a/src/Artemis.UI.Windows/App.axaml.cs +++ b/src/Artemis.UI.Windows/App.axaml.cs @@ -33,7 +33,7 @@ public class App : Application Environment.Exit(1); } - _container = ArtemisBootstrapper.Bootstrap(this, new WindowsModule()); + _container = ArtemisBootstrapper.Bootstrap(this, c => c.RegisterProviders()); Program.CreateLogger(_container); RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); diff --git a/src/Artemis.UI.Windows/DryIoc/ContainerExtensions.cs b/src/Artemis.UI.Windows/DryIoc/ContainerExtensions.cs new file mode 100644 index 000000000..000931d92 --- /dev/null +++ b/src/Artemis.UI.Windows/DryIoc/ContainerExtensions.cs @@ -0,0 +1,27 @@ +using Artemis.Core.Providers; +using Artemis.Core.Services; +using Artemis.UI.Shared.Providers; +using Artemis.UI.Windows.Providers; +using Artemis.UI.Windows.Providers.Input; +using DryIoc; + +namespace Artemis.UI.Windows.DryIoc; + +/// +/// Provides an extension method to register services onto a DryIoc . +/// +public static class UIContainerExtensions +{ + /// + /// Registers providers into the container. + /// + /// The builder building the current container + public static void RegisterProviders(this IContainer container) + { + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + container.Register(); + container.Register(serviceKey: WindowsInputProvider.Id); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/DryIoc/WindowsModule.cs b/src/Artemis.UI.Windows/DryIoc/WindowsModule.cs deleted file mode 100644 index 96b8b7ec7..000000000 --- a/src/Artemis.UI.Windows/DryIoc/WindowsModule.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Artemis.Core.DryIoc; -using Artemis.Core.Providers; -using Artemis.Core.Services; -using Artemis.UI.Shared.Providers; -using Artemis.UI.Windows.Providers; -using Artemis.UI.Windows.Providers.Input; -using DryIoc; - -namespace Artemis.UI.Windows.DryIoc; - -public class WindowsModule : IModule -{ - /// - public void Load(IRegistrator builder) - { - builder.Register(Reuse.Singleton); - builder.Register(Reuse.Singleton); - builder.Register(Reuse.Singleton); - builder.Register(); - builder.Register(serviceKey: WindowsInputProvider.Id); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/ArtemisBootstrapper.cs b/src/Artemis.UI/ArtemisBootstrapper.cs index 2e4a57937..1056070e1 100644 --- a/src/Artemis.UI/ArtemisBootstrapper.cs +++ b/src/Artemis.UI/ArtemisBootstrapper.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Reactive; +using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.DryIoc; using Artemis.UI.DryIoc; @@ -11,6 +12,8 @@ using Artemis.UI.Shared.DataModelPicker; using Artemis.UI.Shared.DryIoc; using Artemis.UI.Shared.Services; using Artemis.VisualScripting.DryIoc; +using Artemis.WebClient.Updating; +using Artemis.WebClient.Updating.DryIoc; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -25,7 +28,7 @@ public static class ArtemisBootstrapper private static Container? _container; private static Application? _application; - public static IContainer Bootstrap(Application application, params IModule[] modules) + public static IContainer Bootstrap(Application application, Action? configureServices = null) { if (_application != null || _container != null) throw new ArtemisUIException("UI already bootstrapped"); @@ -33,18 +36,19 @@ public static class ArtemisBootstrapper Utilities.PrepareFirstLaunch(); _application = application; - _container = new Container(rules => rules.WithConcreteTypeDynamicRegistrations() - .WithoutThrowOnRegisteringDisposableTransient()); + _container = new Container(rules => rules + .WithMicrosoftDependencyInjectionRules() + .WithConcreteTypeDynamicRegistrations() + .WithoutThrowOnRegisteringDisposableTransient()); - new CoreModule().Load(_container); - new UIModule().Load(_container); - new SharedUIModule().Load(_container); - new NoStringDryIocModule().Load(_container); - foreach (IModule module in modules) - module.Load(_container); + _container.RegisterCore(); + _container.RegisterUI(); + _container.RegisterSharedUI(); + _container.RegisterUpdatingClient(); + _container.RegisterNoStringEvaluating(); + configureServices?.Invoke(_container); _container.UseDryIocDependencyResolver(); - return _container; } diff --git a/src/Artemis.UI/DryIoc/ContainerExtensions.cs b/src/Artemis.UI/DryIoc/ContainerExtensions.cs new file mode 100644 index 000000000..f4c484bec --- /dev/null +++ b/src/Artemis.UI/DryIoc/ContainerExtensions.cs @@ -0,0 +1,42 @@ +using System.Reflection; +using Artemis.UI.DryIoc.Factories; +using Artemis.UI.DryIoc.InstanceProviders; +using Artemis.UI.Screens; +using Artemis.UI.Screens.VisualScripting; +using Artemis.UI.Services.Interfaces; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Services.NodeEditor; +using Artemis.UI.Shared.Services.ProfileEditor; +using Avalonia.Platform; +using Avalonia.Shared.PlatformSupport; +using DryIoc; + +namespace Artemis.UI.DryIoc; + +/// +/// Provides an extension method to register services onto a DryIoc . +/// +public static class UIContainerExtensions +{ + /// + /// Registers UI services into the container. + /// + /// The builder building the current container + public static void RegisterUI(this IContainer container) + { + Assembly[] thisAssembly = {typeof(UIContainerExtensions).Assembly}; + + container.RegisterInstance(new AssetLoader(), IfAlreadyRegistered.Throw); + container.Register(Reuse.Singleton); + + container.RegisterMany(thisAssembly, type => type.IsAssignableTo()); + container.RegisterMany(thisAssembly, type => type.IsAssignableTo(), ifAlreadyRegistered: IfAlreadyRegistered.Replace); + container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type.IsInterface); + container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type != typeof(PropertyVmFactory)); + + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + + container.RegisterMany(thisAssembly, type => type.IsAssignableTo(), Reuse.Singleton); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/UiModule.cs b/src/Artemis.UI/DryIoc/UiModule.cs deleted file mode 100644 index 652f730d1..000000000 --- a/src/Artemis.UI/DryIoc/UiModule.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using Artemis.Core.DryIoc; -using Artemis.UI.DryIoc.Factories; -using Artemis.UI.DryIoc.InstanceProviders; -using Artemis.UI.Screens; -using Artemis.UI.Screens.VisualScripting; -using Artemis.UI.Services.Interfaces; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Services.NodeEditor; -using Artemis.UI.Shared.Services.ProfileEditor; -using Avalonia.Platform; -using Avalonia.Shared.PlatformSupport; -using DryIoc; - -namespace Artemis.UI.DryIoc; - -public class UIModule : IModule -{ - public void Load(IRegistrator builder) - { - Assembly thisAssembly = typeof(UIModule).Assembly; - - builder.RegisterInstance(new AssetLoader(), IfAlreadyRegistered.Throw); - builder.Register(Reuse.Singleton); - - builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo()); - builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo(), ifAlreadyRegistered: IfAlreadyRegistered.Replace); - builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo() && type.IsInterface); - builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo() && type != typeof(PropertyVmFactory)); - - builder.Register(Reuse.Singleton); - builder.Register(Reuse.Singleton); - - builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo(), Reuse.Singleton); - } -} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs b/src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs new file mode 100644 index 000000000..6e388f30d --- /dev/null +++ b/src/Artemis.VisualScripting/DryIoc/ContainerExtensions.cs @@ -0,0 +1,40 @@ +using DryIoc; +using Microsoft.Extensions.ObjectPool; +using NoStringEvaluating; +using NoStringEvaluating.Contract; +using NoStringEvaluating.Models.Values; +using NoStringEvaluating.Services.Cache; +using NoStringEvaluating.Services.Checking; +using NoStringEvaluating.Services.Parsing; +using NoStringEvaluating.Services.Parsing.NodeReaders; + +namespace Artemis.VisualScripting.DryIoc; + +/// +/// Provides an extension method to register services onto a DryIoc . +/// +public static class UIContainerExtensions +{ + /// + /// Registers NoStringEvaluating services into the container. + /// + /// The builder building the current container + public static void RegisterNoStringEvaluating(this IContainer container) + { + // Pooling + container.RegisterInstance(ObjectPool.Create>()); + container.RegisterInstance(ObjectPool.Create>()); + container.RegisterInstance(ObjectPool.Create()); + + // Parser + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + container.Register(Reuse.Singleton); + + // Checker + container.Register(Reuse.Singleton); + + // Evaluator + container.Register(Reuse.Singleton); + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/DryIoc/NoStringNinjectModule.cs b/src/Artemis.VisualScripting/DryIoc/NoStringNinjectModule.cs deleted file mode 100644 index 8d3563615..000000000 --- a/src/Artemis.VisualScripting/DryIoc/NoStringNinjectModule.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Artemis.Core.DryIoc; -using DryIoc; -using Microsoft.Extensions.ObjectPool; -using NoStringEvaluating; -using NoStringEvaluating.Contract; -using NoStringEvaluating.Models.Values; -using NoStringEvaluating.Services.Cache; -using NoStringEvaluating.Services.Checking; -using NoStringEvaluating.Services.Parsing; -using NoStringEvaluating.Services.Parsing.NodeReaders; - -namespace Artemis.VisualScripting.DryIoc; - -public class NoStringDryIocModule : IModule -{ - /// - public void Load(IRegistrator builder) - { - // Pooling - builder.RegisterInstance(ObjectPool.Create>()); - builder.RegisterInstance(ObjectPool.Create>()); - builder.RegisterInstance(ObjectPool.Create()); - - // Parser - builder.Register(Reuse.Singleton); - builder.Register(Reuse.Singleton); - builder.Register(Reuse.Singleton); - - // Checker - builder.Register(Reuse.Singleton); - - // Evaluator - builder.Register(Reuse.Singleton); - } -} \ No newline at end of file