A NosSmooth.Extensions.SharedBinding/Extensions/ServiceCollectionExtensions.cs => NosSmooth.Extensions.SharedBinding/Extensions/ServiceCollectionExtensions.cs +98 -0
@@ 0,0 1,98 @@
+//
+// ServiceCollectionExtensions.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using NosSmooth.Data.NOSFiles;
+using NosSmooth.LocalBinding;
+using NosSmooth.PacketSerializer.Packets;
+
+namespace NosSmooth.Extensions.SharedBinding.Extensions;
+
+/// <summary>
+/// Extension methods for <see cref="IServiceProvider"/>.
+/// </summary>
+public static class ServiceCollectionExtensions
+{
+ /// <summary>
+ /// Replaces <see cref="NosBindingManager"/>
+ /// with shared equivalent. That allows for multiple programs injected inside NosTale.
+ /// </summary>
+ /// <param name="serviceCollection">The collection.</param>
+ /// <returns>The same collection.</returns>
+ public static IServiceCollection ShareBinding(this IServiceCollection serviceCollection)
+ {
+ var original = serviceCollection
+ .Last(x => x.ServiceType == typeof(NosBindingManager));
+
+ return serviceCollection
+ .Configure<SharedOptions>(o => o.BindingDescriptor = original)
+ .Replace
+ (ServiceDescriptor.Singleton<NosBindingManager>(p => SharedManager.Instance.GetNosBindingManager(p)));
+ }
+
+ /// <summary>
+ /// Replaces <see cref="NostaleDataFilesManager"/>
+ /// with shared equivalent. That allows for multiple programs injected inside NosTale.
+ /// </summary>
+ /// <param name="serviceCollection">The collection.</param>
+ /// <returns>The same collection.</returns>
+ public static IServiceCollection ShareFileManager(this IServiceCollection serviceCollection)
+ {
+ var original = serviceCollection
+ .Last(x => x.ServiceType == typeof(NostaleDataFilesManager));
+
+ return serviceCollection
+ .Configure<SharedOptions>(o => o.FileDescriptor = original)
+ .Replace
+ (ServiceDescriptor.Singleton<NostaleDataFilesManager>(p => SharedManager.Instance.GetFilesManager(p)));
+ }
+
+ /// <summary>
+ /// Replaces <see cref="IPacketTypesRepository"/>
+ /// with shared equivalent. That allows for multiple programs injected inside NosTale.
+ /// </summary>
+ /// <param name="serviceCollection">The collection.</param>
+ /// <returns>The same collection.</returns>
+ public static IServiceCollection SharePacketRepository(this IServiceCollection serviceCollection)
+ {
+ var original = serviceCollection
+ .Last(x => x.ServiceType == typeof(IPacketTypesRepository));
+
+ return serviceCollection
+ .Configure<SharedOptions>(o => o.PacketRepositoryDescriptor = original)
+ .Replace
+ (
+ ServiceDescriptor.Singleton<IPacketTypesRepository>(p => SharedManager.Instance.GetPacketRepository(p))
+ );
+ }
+
+ /// <summary>
+ /// Replaces <see cref="NosBindingManager"/>, <see cref="NostaleDataFilesManager"/> and <see cref="IPacketTypesRepository"/>
+ /// with their shared equvivalents. That allows for multiple programs injected inside NosTale.
+ /// </summary>
+ /// <param name="serviceCollection">The collection.</param>
+ /// <returns>The same collection.</returns>
+ public static IServiceCollection ShareNosSmooth(this IServiceCollection serviceCollection)
+ {
+ if (serviceCollection.Any(x => x.ServiceType == typeof(NosBindingManager)))
+ {
+ serviceCollection.ShareBinding();
+ }
+
+ if (serviceCollection.Any(x => x.ServiceType == typeof(NostaleDataFilesManager)))
+ {
+ serviceCollection.ShareFileManager();
+ }
+
+ if (serviceCollection.Any(x => x.ServiceType == typeof(IPacketTypesRepository)))
+ {
+ serviceCollection.SharePacketRepository();
+ }
+
+ return serviceCollection;
+ }
+}<
\ No newline at end of file
A NosSmooth.Extensions.SharedBinding/NosSmooth.Extensions.SharedBinding.csproj => NosSmooth.Extensions.SharedBinding/NosSmooth.Extensions.SharedBinding.csproj +18 -0
@@ 0,0 1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net7.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\src\Core\NosSmooth.LocalBinding\NosSmooth.LocalBinding.csproj" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <PackageReference Include="NosSmooth.Data.NOSFiles" Version="2.0.2" />
+ <PackageReference Include="NosSmooth.PacketSerializer" Version="2.0.0" />
+ </ItemGroup>
+
+</Project>
A NosSmooth.Extensions.SharedBinding/SharedManager.cs => NosSmooth.Extensions.SharedBinding/SharedManager.cs +120 -0
@@ 0,0 1,120 @@
+//
+// SharedManager.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using NosSmooth.Data.NOSFiles;
+using NosSmooth.LocalBinding;
+using NosSmooth.PacketSerializer.Packets;
+
+namespace NosSmooth.Extensions.SharedBinding;
+
+/// <summary>
+/// Manager for sharing <see cref="NosBindingManager"/>,
+/// <see cref="NostaleDataFilesManager"/> and
+/// <see cref="IPacketTypesRepository"/>.
+/// </summary>
+public class SharedManager
+{
+ private static SharedManager? _instance;
+ private NosBindingManager? _bindingManager;
+ private NostaleDataFilesManager? _filesManager;
+ private IPacketTypesRepository? _packetRepository;
+
+ /// <summary>
+ /// A singleton instance.
+ /// One per process.
+ /// </summary>
+ public static SharedManager Instance
+ {
+ get
+ {
+ if (_instance is null)
+ {
+ _instance = new SharedManager();
+ }
+
+ return _instance;
+ }
+ }
+
+ /// <summary>
+ /// Gets the shared nos binding manager.
+ /// </summary>
+ /// <param name="services">The service provider.</param>
+ /// <returns>The shared manager.</returns>
+ public NosBindingManager GetNosBindingManager(IServiceProvider services)
+ {
+ if (_bindingManager is null)
+ {
+ _bindingManager = GetFromDescriptor<NosBindingManager>(services, o => o.BindingDescriptor);
+ }
+
+ return _bindingManager;
+
+ }
+
+ /// <summary>
+ /// Gets the shared file manager.
+ /// </summary>
+ /// <param name="services">The service provider.</param>
+ /// <returns>The shared manager.</returns>
+ public NostaleDataFilesManager GetFilesManager(IServiceProvider services)
+ {
+ if (_filesManager is null)
+ {
+ _filesManager = GetFromDescriptor<NostaleDataFilesManager>(services, o => o.FileDescriptor);
+ }
+
+ return _filesManager;
+
+ }
+
+ /// <summary>
+ /// Gets the shared packet type repository.
+ /// </summary>
+ /// <param name="services">The service provider.</param>
+ /// <returns>The shared repository.</returns>
+ public IPacketTypesRepository GetPacketRepository(IServiceProvider services)
+ {
+ if (_packetRepository is null)
+ {
+ _packetRepository = GetFromDescriptor<IPacketTypesRepository>(services, o => o.PacketRepositoryDescriptor);
+ }
+
+ return _packetRepository;
+
+ }
+
+ private T GetFromDescriptor<T>(IServiceProvider services, Func<SharedOptions, ServiceDescriptor?> getDescriptor)
+ {
+ var options = services.GetRequiredService<IOptions<SharedOptions>>();
+ var descriptor = getDescriptor(options.Value);
+
+ if (descriptor is null)
+ {
+ throw new InvalidOperationException
+ ($"Could not find {typeof(T)} in the service provider when trying to make a shared instance.");
+ }
+
+ if (descriptor.ImplementationInstance is not null)
+ {
+ return (T)descriptor.ImplementationInstance;
+ }
+
+ if (descriptor.ImplementationFactory is not null)
+ {
+ return (T)descriptor.ImplementationFactory(services);
+ }
+
+ if (descriptor.ImplementationType is not null)
+ {
+ return (T)ActivatorUtilities.CreateInstance(services, descriptor.ImplementationType);
+ }
+
+ return ActivatorUtilities.CreateInstance<T>(services);
+ }
+}<
\ No newline at end of file
A NosSmooth.Extensions.SharedBinding/SharedOptions.cs => NosSmooth.Extensions.SharedBinding/SharedOptions.cs +33 -0
@@ 0,0 1,33 @@
+//
+// SharedOptions.cs
+//
+// Copyright (c) František Boháček. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Microsoft.Extensions.DependencyInjection;
+using NosSmooth.Data.NOSFiles;
+using NosSmooth.LocalBinding;
+using NosSmooth.PacketSerializer.Packets;
+
+namespace NosSmooth.Extensions.SharedBinding;
+
+/// <summary>
+/// Options for <see cref="SharedManager"/>.
+/// </summary>
+internal class SharedOptions
+{
+ /// <summary>
+ /// Gets or sets the original descriptor of <see cref="NosBindingManager"/>.
+ /// </summary>
+ public ServiceDescriptor? BindingDescriptor { get; set; }
+
+ /// <summary>
+ /// Gets or sets the original descriptor of <see cref="NostaleDataFilesManager"/>.
+ /// </summary>
+ public ServiceDescriptor? FileDescriptor { get; set; }
+
+ /// <summary>
+ /// Gets or sets the original descriptor of <see cref="IPacketTypesRepository"/>.
+ /// </summary>
+ public ServiceDescriptor? PacketRepositoryDescriptor { get; set; }
+}<
\ No newline at end of file