protected OpenModPluginBase(IServiceProvider serviceProvider) { m_ServiceProvider = serviceProvider; LifetimeScope = serviceProvider.GetRequiredService <ILifetimeScope>(); Configuration = serviceProvider.GetRequiredService <IConfiguration>(); DataStore = serviceProvider.GetRequiredService <IDataStore>(); Runtime = serviceProvider.GetRequiredService <IRuntime>(); EventBus = serviceProvider.GetRequiredService <IEventBus>(); m_LoggerFactory = serviceProvider.GetRequiredService <ILoggerFactory>(); m_CommandStoreOptions = serviceProvider.GetRequiredService <IOptions <CommandStoreOptions> >(); var metadata = GetType().Assembly.GetCustomAttribute <PluginMetadataAttribute>(); OpenModComponentId = metadata.Id; Version = GetPluginVersion(); DisplayName = !string.IsNullOrEmpty(metadata.DisplayName) ? metadata.DisplayName ! : metadata.Id; Author = metadata.Author; Website = metadata.Website; Description = metadata.Description; WorkingDirectory = PluginHelper.GetWorkingDirectory(Runtime, metadata.Id); }
public async Task <IOpenModPlugin> TryActivatePluginAsync(Assembly assembly) { if (m_IsDisposing) { throw new ObjectDisposedException(nameof(PluginActivator)); } var pluginMetadata = assembly.GetCustomAttribute <PluginMetadataAttribute>(); if (pluginMetadata == null) { m_Logger.LogError($"Failed to load plugin from assembly {assembly}: couldn't find any plugin metadata"); return(null); } var pluginTypes = assembly.FindTypes <IOpenModPlugin>(false).ToList(); if (pluginTypes.Count == 0) { m_Logger.LogError($"Failed to load plugin from assembly {assembly}: couldn't find any IOpenModPlugin implementation"); return(null); } if (pluginTypes.Count > 1) { m_Logger.LogError($"Failed to load plugin from assembly {assembly}: assembly has multiple IOpenModPlugin instances"); return(null); } var pluginType = pluginTypes.Single(); IOpenModPlugin pluginInstance; try { var serviceProvider = m_LifetimeScope.Resolve <IServiceProvider>(); var lifetimeScope = m_LifetimeScope.BeginLifetimeScope(containerBuilder => { var workingDirectory = PluginHelper.GetWorkingDirectory(m_Runtime, pluginMetadata.Id); var configurationBuilder = new ConfigurationBuilder(); if (Directory.Exists(workingDirectory)) { configurationBuilder .SetBasePath(workingDirectory) .AddYamlFile("config.yaml", optional: true, reloadOnChange: true); } var configuration = configurationBuilder .AddEnvironmentVariables(pluginMetadata.Id.Replace(".", "_") + "_") .Build(); containerBuilder.Register(context => configuration) .As <IConfiguration>() .As <IConfigurationRoot>() .SingleInstance() .OwnedByLifetimeScope(); containerBuilder.RegisterType(pluginType) .As(pluginType) .As <IOpenModPlugin>() .SingleInstance() .ExternallyOwned(); containerBuilder.Register(context => m_DataStoreFactory.CreateDataStore(null, workingDirectory)) .As <IDataStore>() .SingleInstance() .OwnedByLifetimeScope(); var stringLocalizer = m_StringLocalizerFactory.Create("translations", workingDirectory); containerBuilder.Register(context => stringLocalizer) .As <IStringLocalizer>() .SingleInstance() .OwnedByLifetimeScope(); foreach (var type in pluginType.Assembly.FindTypes <IPluginContainerConfigurator>()) { var configurator = (IPluginContainerConfigurator)ActivatorUtilities.CreateInstance(serviceProvider, type); configurator.ConfigureContainer(containerBuilder); } }); pluginInstance = (IOpenModPlugin)lifetimeScope.Resolve(pluginType); } catch (Exception ex) { m_Logger.LogError(ex, $"Failed to load plugin from type: {pluginType.FullName} in assembly: {assembly.FullName}"); return(null); } try { await pluginInstance.LoadAsync(); } catch (Exception ex) { m_Logger.LogError(ex, $"Failed to load plugin: {pluginInstance.DisplayName} v{pluginInstance.Version}"); return(null); } m_ActivatedPlugins.Add(new WeakReference(pluginInstance)); return(pluginInstance); }
public async Task <IOpenModPlugin> TryActivatePluginAsync(Assembly assembly) { try { if (m_IsDisposing) { throw new ObjectDisposedException(nameof(PluginActivator)); } var pluginMetadata = assembly.GetCustomAttribute <PluginMetadataAttribute>(); if (pluginMetadata == null) { m_Logger.LogError( $"Failed to load plugin from assembly {assembly}: couldn't find any plugin metadata"); return(null); } var pluginTypes = assembly.FindTypes <IOpenModPlugin>(false).ToList(); if (pluginTypes.Count == 0) { m_Logger.LogError( $"Failed to load plugin from assembly {assembly}: couldn't find any IOpenModPlugin implementation"); return(null); } if (pluginTypes.Count > 1) { m_Logger.LogError( $"Failed to load plugin from assembly {assembly}: assembly has multiple IOpenModPlugin instances"); return(null); } var pluginType = pluginTypes.Single(); IOpenModPlugin pluginInstance; try { var serviceProvider = m_LifetimeScope.Resolve <IServiceProvider>(); var lifetimeScope = m_LifetimeScope.BeginLifetimeScope(containerBuilder => { var workingDirectory = PluginHelper.GetWorkingDirectory(m_Runtime, pluginMetadata.Id); var configurationBuilder = new ConfigurationBuilder(); if (Directory.Exists(workingDirectory)) { configurationBuilder .SetBasePath(workingDirectory) .AddYamlFile("config.yaml", optional: true, reloadOnChange: true); } var configuration = configurationBuilder .AddEnvironmentVariables(pluginMetadata.Id.Replace(".", "_") + "_") .Build(); containerBuilder.Register(context => configuration) .As <IConfiguration>() .As <IConfigurationRoot>() .SingleInstance() .OwnedByLifetimeScope(); containerBuilder.RegisterType(pluginType) .AsSelf() .As <IOpenModComponent>() .As <IOpenModPlugin>() .SingleInstance() .OwnedByLifetimeScope(); containerBuilder.RegisterType <ScopedPermissionChecker>() .As <IPermissionChecker>() .InstancePerLifetimeScope() .OwnedByLifetimeScope(); containerBuilder.Register(context => m_DataStoreFactory.CreateDataStore(new DataStoreCreationParameters { ComponentId = pluginMetadata.Id, Prefix = null, Suffix = "data", WorkingDirectory = workingDirectory })) .As <IDataStore>() .SingleInstance() .OwnedByLifetimeScope(); var stringLocalizer = Directory.Exists(workingDirectory) ? m_StringLocalizerFactory.Create("translations", workingDirectory) : NullStringLocalizer.Instance; containerBuilder.Register(context => stringLocalizer) .As <IStringLocalizer>() .SingleInstance() .OwnedByLifetimeScope(); var services = ServiceRegistrationHelper.FindFromAssembly <PluginServiceImplementationAttribute>(assembly, m_Logger); var servicesRegistrations = services.OrderBy(d => d.Priority, new PriorityComparer(PriortyComparisonMode.LowestFirst)); foreach (var servicesRegistration in servicesRegistrations) { var implementationType = servicesRegistration.ServiceImplementationType; containerBuilder.RegisterType(implementationType) .As(implementationType) .WithLifetime(servicesRegistration.Lifetime) .OwnedByLifetimeScope(); foreach (var service in servicesRegistration.ServiceTypes) { containerBuilder.Register(c => c.Resolve(implementationType)) .As(service) .WithLifetime(servicesRegistration.Lifetime) .OwnedByLifetimeScope(); } } foreach (var type in pluginType.Assembly.FindTypes <IPluginContainerConfigurator>()) { var configurator = (IPluginContainerConfigurator)ActivatorUtilities.CreateInstance(serviceProvider, type); configurator.ConfigureContainer(new PluginServiceConfigurationContext(m_LifetimeScope, configuration, containerBuilder)); } var configurationEvent = new PluginContainerConfiguringEvent(pluginMetadata, pluginType, configuration, containerBuilder, workingDirectory); AsyncHelper.RunSync(() => m_EventBus.EmitAsync(m_Runtime, this, configurationEvent)); }); pluginInstance = (IOpenModPlugin)lifetimeScope.Resolve(pluginType); var pluginActivateEvent = new PluginActivatingEvent(pluginInstance); await m_EventBus.EmitAsync(m_Runtime, this, pluginActivateEvent); if (pluginActivateEvent.IsCancelled) { await lifetimeScope.DisposeAsync(); return(null); } } catch (Exception ex) { m_Logger.LogError(ex, $"Failed to load plugin from type: {pluginType.FullName} in assembly: {assembly.FullName}"); return(null); } try { await pluginInstance.LoadAsync(); var serviceProvider = pluginInstance.LifetimeScope.Resolve <IServiceProvider>(); var pluginHelpWriter = ActivatorUtilities.CreateInstance <PluginHelpWriter>(serviceProvider); await pluginHelpWriter.WriteHelpFileAsync(); } catch (Exception ex) { m_Logger.LogError(ex, $"Failed to load plugin: {pluginInstance.DisplayName} v{pluginInstance.Version}"); try { await pluginInstance.LifetimeScope.DisposeAsync(); } catch (Exception e) { m_Logger.LogError(e, "Failed to unload plugin: {DisplayName} v{Version}", pluginInstance.DisplayName, pluginInstance.Version); } return(null); } m_ActivatedPlugins.Add(new WeakReference(pluginInstance)); return(pluginInstance); } catch (Exception ex) { m_Logger.LogError(ex, $"Failed to load plugin from assembly: {assembly.FullName}"); return(null); } }