- Added ISystem (automatically run services) service type.
This commit is contained in:
@@ -215,7 +215,7 @@ namespace Barotrauma
|
|||||||
servicesProvider.RegisterServiceType<IPackageManagementServiceConfig, PackageManagementServiceConfig>(ServiceLifetime.Singleton);
|
servicesProvider.RegisterServiceType<IPackageManagementServiceConfig, PackageManagementServiceConfig>(ServiceLifetime.Singleton);
|
||||||
|
|
||||||
// gen IL
|
// gen IL
|
||||||
servicesProvider.Compile();
|
servicesProvider.CompileAndRun();
|
||||||
return servicesProvider;
|
return servicesProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -12,7 +15,14 @@ public class ServicesProvider : IServicesProvider
|
|||||||
{
|
{
|
||||||
private ServiceContainer _serviceContainerInst;
|
private ServiceContainer _serviceContainerInst;
|
||||||
private ServiceContainer ServiceContainer => _serviceContainerInst;
|
private ServiceContainer ServiceContainer => _serviceContainerInst;
|
||||||
|
/// <summary>
|
||||||
|
/// Definition: [Key: InterfaceType, Value: ConcreteTypes]
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<Type, ConcurrentBag<Type>> _systemTypeDefs = new();
|
||||||
|
/// <summary>
|
||||||
|
/// Definition: [Key: ConcreteType, Value: TypeInstance]
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<Type, ISystem> _systemInstances = new();
|
||||||
private readonly ReaderWriterLockSlim _serviceLock = new();
|
private readonly ReaderWriterLockSlim _serviceLock = new();
|
||||||
|
|
||||||
public ServicesProvider()
|
public ServicesProvider()
|
||||||
@@ -27,6 +37,13 @@ public class ServicesProvider : IServicesProvider
|
|||||||
|
|
||||||
public void RegisterServiceType<TSvcInterface, TService>(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface
|
public void RegisterServiceType<TSvcInterface, TService>(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface
|
||||||
{
|
{
|
||||||
|
// ISystem services must run as a lifetime singleton
|
||||||
|
if (typeof(TSvcInterface).IsAssignableTo(typeof(ISystem)))
|
||||||
|
{
|
||||||
|
lifetimeInstance = new PerContainerLifetime();
|
||||||
|
_systemTypeDefs.GetOrAdd(typeof(TSvcInterface), (type) => new ConcurrentBag<Type>());
|
||||||
|
}
|
||||||
|
|
||||||
if (lifetimeInstance is null)
|
if (lifetimeInstance is null)
|
||||||
{
|
{
|
||||||
switch (lifetime)
|
switch (lifetime)
|
||||||
@@ -54,7 +71,6 @@ public class ServicesProvider : IServicesProvider
|
|||||||
ServiceContainer.Register<TSvcInterface, TService>(lifetimeInstance);
|
ServiceContainer.Register<TSvcInterface, TService>(lifetimeInstance);
|
||||||
else
|
else
|
||||||
ServiceContainer.Register<TSvcInterface, TService>();
|
ServiceContainer.Register<TSvcInterface, TService>();
|
||||||
OnServiceRegistered?.Invoke(typeof(TSvcInterface), typeof(TService));
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -70,6 +86,13 @@ public class ServicesProvider : IServicesProvider
|
|||||||
throw new ArgumentNullException($"Tried to register a service of type {typeof(TService).Name} but the name provided is null or empty." );
|
throw new ArgumentNullException($"Tried to register a service of type {typeof(TService).Name} but the name provided is null or empty." );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ISystem services must run as a lifetime singleton
|
||||||
|
if (typeof(TSvcInterface).IsAssignableTo(typeof(ISystem)))
|
||||||
|
{
|
||||||
|
lifetimeInstance = new PerContainerLifetime();
|
||||||
|
_systemTypeDefs.GetOrAdd(typeof(TSvcInterface), (type) => new ConcurrentBag<Type>());
|
||||||
|
}
|
||||||
|
|
||||||
if (lifetimeInstance is null)
|
if (lifetimeInstance is null)
|
||||||
{
|
{
|
||||||
switch (lifetime)
|
switch (lifetime)
|
||||||
@@ -94,7 +117,6 @@ public class ServicesProvider : IServicesProvider
|
|||||||
{
|
{
|
||||||
_serviceLock.EnterReadLock();
|
_serviceLock.EnterReadLock();
|
||||||
ServiceContainer.Register<TSvcInterface, TService>(name, lifetimeInstance);
|
ServiceContainer.Register<TSvcInterface, TService>(name, lifetimeInstance);
|
||||||
OnServiceRegistered?.Invoke(typeof(TSvcInterface), typeof(TService));
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -115,21 +137,27 @@ public class ServicesProvider : IServicesProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Compile()
|
public void CompileAndRun()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_serviceLock.EnterReadLock();
|
_serviceLock.EnterWriteLock();
|
||||||
ServiceContainer?.Compile();
|
ServiceContainer?.Compile();
|
||||||
|
foreach (var typeDef in _systemTypeDefs.Values.SelectMany(type => type))
|
||||||
|
{
|
||||||
|
if (_systemInstances.ContainsKey(typeDef))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_systemInstances[typeDef] = (ISystem)ServiceContainer?.TryGetInstance(typeDef);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_serviceLock.ExitReadLock();
|
_serviceLock.ExitWriteLock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public event Action<Type, Type> OnServiceRegistered;
|
|
||||||
|
|
||||||
public void InjectServices<T>(T inst) where T : class
|
public void InjectServices<T>(T inst) where T : class
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -209,19 +237,32 @@ public class ServicesProvider : IServicesProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.Synchronized)]
|
||||||
public void DisposeAndReset()
|
public void DisposeAndReset()
|
||||||
{
|
{
|
||||||
// Plugins should never be allowed to execute this.
|
// Plugins should never be allowed to execute this.
|
||||||
if (Assembly.GetCallingAssembly() != Assembly.GetExecutingAssembly())
|
if (Assembly.GetCallingAssembly() != Assembly.GetExecutingAssembly())
|
||||||
{
|
{
|
||||||
throw new MethodAccessException(
|
throw new MethodAccessException(
|
||||||
$"Assembly {Assembly.GetCallingAssembly().FullName} attempted to call DisposeAllServices().");
|
$"Assembly {Assembly.GetCallingAssembly().FullName} attempted to call {nameof(DisposeAndReset)}().");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_serviceLock.EnterWriteLock();
|
_serviceLock.EnterWriteLock();
|
||||||
|
foreach (var system in _systemInstances.Values)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
system.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// ignored, no logging services available.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_systemInstances.Clear();
|
||||||
|
_systemTypeDefs.Clear();
|
||||||
_serviceContainerInst?.Dispose();
|
_serviceContainerInst?.Dispose();
|
||||||
_serviceContainerInst = new ServiceContainer();
|
_serviceContainerInst = new ServiceContainer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ using Microsoft.Toolkit.Diagnostics;
|
|||||||
|
|
||||||
namespace Barotrauma.LuaCs;
|
namespace Barotrauma.LuaCs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a <see cref="IReusableService"/> that is automatically instantiated at startup for the lifetime of the
|
||||||
|
/// <see cref="IServiceProvider"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public interface ISystem : IReusableService { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a service that can be reset to it's post-constructor state and reused without needing to be disposed.
|
/// Defines a service that can be reset to it's post-constructor state and reused without needing to be disposed.
|
||||||
/// Intended for persistent services.
|
/// Intended for persistent services.
|
||||||
|
|||||||
+15
-19
@@ -6,7 +6,8 @@ using LightInject;
|
|||||||
namespace Barotrauma.LuaCs;
|
namespace Barotrauma.LuaCs;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides instancing and management of IServices.
|
/// Provides instancing and management of <see cref="IService"/>, <see cref="IReusableService"/>, and <see cref="ISystem"/>
|
||||||
|
/// instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IServicesProvider
|
public interface IServicesProvider
|
||||||
{
|
{
|
||||||
@@ -15,29 +16,24 @@ public interface IServicesProvider
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a type as a service for a given interface.
|
/// Registers a type as a service for a given interface.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lifetime"></param>
|
/// <remarks>NOTE: <see cref="ISystem"/> services are forced to <see cref="ServiceLifetime.Singleton"/></remarks>
|
||||||
/// <param name="lifetimeInstance"></param>
|
/// <param name="lifetime">The <see cref="ServiceLifetime"/> of the service when requested.</param>
|
||||||
/// <typeparam name="TSvcInterface"></typeparam>
|
/// <param name="lifetimeInstance">Custom lifetime instance.</param>
|
||||||
/// <typeparam name="TService"></typeparam>
|
/// <typeparam name="TSvcInterface">Service interface.</typeparam>
|
||||||
|
/// <typeparam name="TService">Implementing service type.</typeparam>
|
||||||
void RegisterServiceType<TSvcInterface, TService>(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface;
|
void RegisterServiceType<TSvcInterface, TService>(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a type as a service for a given interface that can be requested by name.
|
/// Registers a type as a service for a given interface that can be requested by name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name"></param>
|
/// <remarks>NOTE: <see cref="ISystem"/> services are forced to <see cref="ServiceLifetime.Singleton"/></remarks>
|
||||||
/// <param name="lifetime"></param>
|
/// <param name="name">Name of the service for lookup.</param>
|
||||||
/// <param name="lifetimeInstance"></param>
|
/// <param name="lifetime">The <see cref="ServiceLifetime"/> of the service when requested.</param>
|
||||||
/// <typeparam name="TSvcInterface"></typeparam>
|
/// <param name="lifetimeInstance">Custom lifetime instance.</param>
|
||||||
/// <typeparam name="TService"></typeparam>
|
/// <typeparam name="TSvcInterface">Service interface.</typeparam>
|
||||||
|
/// <typeparam name="TService">Implementing service type.</typeparam>
|
||||||
void RegisterServiceType<TSvcInterface, TService>(string name, ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface;
|
void RegisterServiceType<TSvcInterface, TService>(string name, ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called whenever a new service type for a given interface is implemented.
|
|
||||||
/// Args[0]: Interface type
|
|
||||||
/// Args[1]: Implementing type
|
|
||||||
/// </summary>
|
|
||||||
event System.Action<Type, Type> OnServiceRegistered;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a factory for resolving the service type.
|
/// Registers a factory for resolving the service type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -46,9 +42,9 @@ public interface IServicesProvider
|
|||||||
void RegisterServiceResolver<TSvcInterface>(Func<ServiceContainer, TSvcInterface> factory) where TSvcInterface : class, IService;
|
void RegisterServiceResolver<TSvcInterface>(Func<ServiceContainer, TSvcInterface> factory) where TSvcInterface : class, IService;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs compilation of registered services.
|
/// Compiles/Generates IL for registered services and instantiates all registered <see cref="ISystem"/> types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Compile();
|
public void CompileAndRun();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user