示例#1
0
        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);
        }
示例#2
0
        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);
        }
示例#3
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)
                        .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);
            }
        }