From 4ef0142747c4a0dd0c4cb71d8e7359c03b3a2942 Mon Sep 17 00:00:00 2001 From: vnugent Date: Tue, 2 Jan 2024 02:33:05 -0500 Subject: breaking changes: plugin service pools & move plugin api away from web related --- .../src/SharedPluginServiceProvider.cs | 115 +++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 lib/Plugins.Runtime/src/SharedPluginServiceProvider.cs (limited to 'lib/Plugins.Runtime/src/SharedPluginServiceProvider.cs') diff --git a/lib/Plugins.Runtime/src/SharedPluginServiceProvider.cs b/lib/Plugins.Runtime/src/SharedPluginServiceProvider.cs new file mode 100644 index 0000000..a64ede3 --- /dev/null +++ b/lib/Plugins.Runtime/src/SharedPluginServiceProvider.cs @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Runtime +* File: SharedPluginServiceProvider.cs +* +* SharedPluginServiceProvider.cs is part of VNLib.Plugins.Runtime which +* is part of the larger VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Runtime is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published +* by the Free Software Foundation, either version 2 of the License, +* or (at your option) any later version. +* +* VNLib.Plugins.Runtime is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with VNLib.Plugins.Runtime. If not, see http://www.gnu.org/licenses/. +*/ + +using System; +using System.ComponentModel.Design; + +using VNLib.Utils; +using VNLib.Plugins.Runtime.Services; + +namespace VNLib.Plugins.Runtime +{ + /// + /// Represents a single shared pool for a collection of plugins to + /// export services to. + /// + public sealed class SharedPluginServiceProvider : + VnDisposeable, + IServiceProvider, + IPluginEventListener + { + private readonly ServiceContainer _serviceContainer = new(); + private readonly object _syncRoot = new(); + + /// + public object? GetService(Type serviceType) => _serviceContainer.GetService(serviceType); + + /// + /// Gets the service object of the specified type. + /// + /// + /// + /// A service object of type serviceType. -or- null if + /// there is no service object of type serviceType. + /// + public T? GetService() where T : class => GetService(typeof(T)) as T; + + void IPluginEventListener.OnPluginLoaded(PluginController controller, object? state) + { + //Add services + AddOrRemoveServices(controller, true); + } + + void IPluginEventListener.OnPluginUnloaded(PluginController controller, object? state) + { + //Remove services + AddOrRemoveServices(controller, false); + } + + private void AddOrRemoveServices(PluginController controller, bool add) + { + /* + * Depending on when services are loaded/unloaded, this instances + * may be disposeed so avoid raising an exception for a condition + * that doenst matter. If disposed, we dont need to clean anything up + */ + if (Disposed) + { + return; + } + + //Get all exported services + PluginServiceExport[] exports = controller.GetExportedServices(); + + //We need to hold a lock to synchronize access to the service container + lock (_syncRoot) + { + //if add flag is set, add the serivces, otherwise remove them + if (add) + { + Array.ForEach(exports, e => _serviceContainer.AddService(e.ServiceType, e.Service)); + } + else + { + Array.ForEach(exports, e => _serviceContainer.RemoveService(e.ServiceType)); + } + } + + //cleanup any disposable services when removing + if (!add) + { + foreach(PluginServiceExport export in exports) + { + if(export.Service is IDisposable disposable) + { + disposable.Dispose(); + } + } + } + } + + /// + protected override void Free() => _serviceContainer.Dispose(); + } +} -- cgit