Skip to content

Commit 7fa0a83

Browse files
- Completed pre-test ServicesProvider implementation.
1 parent ef91d6e commit 7fa0a83

File tree

2 files changed

+131
-37
lines changed

2 files changed

+131
-37
lines changed

Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/IServicesProvider.cs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
34
using LightInject;
45

56
namespace Barotrauma.LuaCs.Services;
@@ -29,20 +30,18 @@ public interface IServicesProvider
2930
/// <typeparam name="TSvcInterface"></typeparam>
3031
/// <typeparam name="TService"></typeparam>
3132
void RegisterServiceType<TSvcInterface, TService>(string name, ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface, new();
32-
33-
/// <summary>
34-
/// Removes a type's registration from being available for the given interface.
35-
/// </summary>
36-
/// <typeparam name="TSvcInterface"></typeparam>
37-
/// <typeparam name="TService"></typeparam>
38-
void UnregisterServiceType<TSvcInterface, TService>() where TSvcInterface : class, IService where TService : class, IService, TSvcInterface, new();
3933

4034
/// <summary>
4135
/// Called whenever a new service type for a given interface is implemented.
4236
/// Args[0]: Interface type
4337
/// Args[1]: Implementing type
4438
/// </summary>
4539
event System.Action<Type, Type> OnServiceRegistered;
40+
41+
/// <summary>
42+
/// Runs compilation of registered services.
43+
/// </summary>
44+
public void Compile();
4645

4746
#endregion
4847

@@ -62,7 +61,7 @@ public interface IServicesProvider
6261
/// <param name="lifetime"></param>
6362
/// <typeparam name="TSvcInterface"></typeparam>
6463
/// <returns></returns>
65-
bool TryGetService<TSvcInterface>(out IService service, out ServiceLifetime lifetime) where TSvcInterface : class, IService;
64+
bool TryGetService<TSvcInterface>(out IService service) where TSvcInterface : class, IService;
6665

6766
/// <summary>
6867
/// Tries to get a service for the given name and interface, returns success/failure.
@@ -72,7 +71,7 @@ public interface IServicesProvider
7271
/// <param name="lifetime"></param>
7372
/// <typeparam name="TSvcInterface"></typeparam>
7473
/// <returns></returns>
75-
bool TryGetService<TSvcInterface>(string name, out IService service, out ServiceLifetime lifetime) where TSvcInterface : class, IService;
74+
bool TryGetService<TSvcInterface>(string name, out IService service) where TSvcInterface : class, IService;
7675

7776
/// <summary>
7877
/// Called whenever a new service is created/instanced.
@@ -90,22 +89,17 @@ public interface IServicesProvider
9089
/// </summary>
9190
/// <typeparam name="TSvc"></typeparam>
9291
/// <returns></returns>
93-
List<TSvc> GetAllServices<TSvc>() where TSvc : class, IService;
92+
ImmutableArray<TSvc> GetAllServices<TSvc>() where TSvc : class, IService;
9493

9594
#endregion
9695

96+
// Notes: Left public due to the common use of Publicizers
9797
#region Internal_Use
9898

9999
/// <summary>
100-
/// Disposes of all services for a type. Warning: unable to dispose of services held by other objects.
101-
/// </summary>
102-
/// <typeparam name="TSvc"></typeparam>
103-
internal void DisposeServicesOfType<TSvc>() where TSvc : class, IService;
104-
105-
/// <summary>
106-
/// Disposes of all services and resets DI container. Warning: unable to dispose of services held by other objects.
100+
/// Notes: Internal use only if hosted by LuaCsForBarotrauma. Disposes of all services and resets DI container. Warning: unable to dispose of services held by other objects.
107101
/// </summary>
108-
internal void DisposeAllServices();
102+
void DisposeAndReset();
109103

110104
#endregion
111105
}

Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ServicesProvider.cs

Lines changed: 119 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
4+
using System.Reflection;
5+
using System.Runtime.CompilerServices;
36
using System.Threading;
47
using LightInject;
58

69
namespace Barotrauma.LuaCs.Services;
710

11+
812
public class ServicesProvider : IServicesProvider
913
{
10-
private ServiceContainer _serviceContainer = new();
14+
private ServiceContainer _serviceContainerInst;
15+
private ServiceContainer ServiceContainer
16+
{
17+
get
18+
{
19+
// ReSharper disable once ConvertIfStatementToNullCoalescingExpression
20+
if (_serviceContainerInst is null)
21+
_serviceContainerInst = new ServiceContainer();
22+
return _serviceContainerInst;
23+
}
24+
}
25+
26+
private readonly ReaderWriterLockSlim _serviceLock = new();
1127

1228
public void RegisterServiceType<TSvcInterface, TService>(ServiceLifetime lifetime, ILifetime lifetimeInstance = null) where TSvcInterface : class, IService where TService : class, IService, TSvcInterface, new()
1329
{
@@ -30,8 +46,18 @@ public class ServicesProvider : IServicesProvider
3046
break;
3147
}
3248
}
33-
34-
_serviceContainer.Register<TSvcInterface, TService>(lifetimeInstance);
49+
50+
try
51+
{
52+
_serviceLock.EnterReadLock();
53+
ServiceContainer.Register<TSvcInterface, TService>(lifetimeInstance);
54+
ServiceContainer.Compile<TService>();
55+
OnServiceRegistered?.Invoke(typeof(TSvcInterface), typeof(TService));
56+
}
57+
finally
58+
{
59+
_serviceLock.ExitReadLock();
60+
}
3561
}
3662

3763
public void RegisterServiceType<TSvcInterface, TService>(string name, ServiceLifetime lifetime,
@@ -62,46 +88,120 @@ public void RegisterServiceType<TSvcInterface, TService>(string name, ServiceLif
6288
}
6389
}
6490

65-
_serviceContainer.Register<TSvcInterface, TService>(name, lifetimeInstance);
91+
try
92+
{
93+
_serviceLock.EnterReadLock();
94+
ServiceContainer.Register<TSvcInterface, TService>(name, lifetimeInstance);
95+
ServiceContainer.Compile<TService>();
96+
OnServiceRegistered?.Invoke(typeof(TSvcInterface), typeof(TService));
97+
}
98+
finally
99+
{
100+
_serviceLock.ExitReadLock();
101+
}
66102
}
67103

68-
public void UnregisterServiceType<TSvcInterface, TService>() where TSvcInterface : class, IService where TService : class, IService, TSvcInterface, new()
104+
public void Compile()
69105
{
70-
throw new NotImplementedException();
106+
try
107+
{
108+
_serviceLock.EnterReadLock();
109+
ServiceContainer?.Compile();
110+
}
111+
finally
112+
{
113+
_serviceLock.ExitReadLock();
114+
}
71115
}
72116

73117
public event Action<Type, Type> OnServiceRegistered;
74118

75119
public void InjectServices<T>(T inst) where T : class
76120
{
77-
throw new NotImplementedException();
121+
try
122+
{
123+
_serviceLock.EnterReadLock();
124+
ServiceContainer.InjectProperties(inst);
125+
}
126+
finally
127+
{
128+
_serviceLock.ExitReadLock();
129+
}
78130
}
79131

80-
public bool TryGetService<TSvcInterface>(out IService service, out ServiceLifetime lifetime) where TSvcInterface : class, IService
132+
public bool TryGetService<TSvcInterface>(out IService service) where TSvcInterface : class, IService
81133
{
82-
throw new NotImplementedException();
134+
try
135+
{
136+
_serviceLock.EnterReadLock();
137+
service = ServiceContainer.TryGetInstance<TSvcInterface>();
138+
return service is not null;
139+
}
140+
catch
141+
{
142+
service = null;
143+
return false;
144+
}
145+
finally
146+
{
147+
_serviceLock.ExitReadLock();
148+
}
83149
}
84150

85-
public bool TryGetService<TSvcInterface>(string name, out IService service, out ServiceLifetime lifetime) where TSvcInterface : class, IService
151+
public bool TryGetService<TSvcInterface>(string name, out IService service) where TSvcInterface : class, IService
86152
{
87-
throw new NotImplementedException();
153+
try
154+
{
155+
_serviceLock.EnterReadLock();
156+
service = ServiceContainer.TryGetInstance<TSvcInterface>(name);
157+
return service is not null;
158+
}
159+
catch
160+
{
161+
service = null;
162+
return false;
163+
}
164+
finally
165+
{
166+
_serviceLock.ExitReadLock();
167+
}
88168
}
89169

90170
public event Action<Type, IService> OnServiceInstanced;
91171

92-
public List<TSvc> GetAllServices<TSvc>() where TSvc : class, IService
172+
public ImmutableArray<TSvc> GetAllServices<TSvc>() where TSvc : class, IService
93173
{
94-
throw new NotImplementedException();
174+
try
175+
{
176+
_serviceLock.EnterReadLock();
177+
return ServiceContainer.GetAllInstances<TSvc>().ToImmutableArray();
178+
}
179+
finally
180+
{
181+
_serviceLock.ExitReadLock();
182+
}
95183
}
96184

97-
public void DisposeServicesOfType<TSvc>() where TSvc : class, IService
185+
[MethodImpl(MethodImplOptions.Synchronized | MethodImplOptions.PreserveSig | MethodImplOptions.NoInlining)]
186+
public void DisposeAndReset()
98187
{
99-
throw new NotImplementedException();
100-
}
188+
// Plugins should never be allowed to execute this.
189+
if (Assembly.GetCallingAssembly() != Assembly.GetExecutingAssembly())
190+
{
191+
throw new MethodAccessException(
192+
$"Assembly {Assembly.GetCallingAssembly().FullName} attempted to call DisposeAllServices().");
193+
}
101194

102-
public void DisposeAllServices()
103-
{
104-
throw new NotImplementedException();
195+
try
196+
{
197+
_serviceLock.EnterWriteLock();
198+
_serviceContainerInst.Dispose();
199+
_serviceContainerInst = new ServiceContainer();
200+
}
201+
finally
202+
{
203+
_serviceLock.ExitWriteLock();
204+
}
105205
}
106206
}
107207

0 commit comments

Comments
 (0)