示例#1
0
        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)
                        .As(pluginType)
                        .As <IOpenModComponent>()
                        .As <IOpenModPlugin>()
                        .SingleInstance()
                        .ExternallyOwned();

                        containerBuilder.RegisterType <ScopedPermissionChecker>()
                        .As <IPermissionChecker>()
                        .InstancePerLifetimeScope()
                        .OwnedByLifetimeScope();

                        containerBuilder.Register(context => m_DataStoreFactory.CreateDataStore(null, 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 PluginContainerConfigurationEvent(pluginMetadata, pluginType,
                                                                                       configuration, containerBuilder, workingDirectory);
                        AsyncHelper.RunSync(() => m_EventBus.EmitAsync(m_Runtime, this, configurationEvent));
                    });

                    pluginInstance = (IOpenModPlugin)lifetimeScope.Resolve(pluginType);
                    var pluginActivateEvent = new PluginActivateEvent(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}");
                    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);
            }
        }