Example #1
0
        public ICommandContext CreateContext(ICommandActor actor, string[] args, string prefix, IReadOnlyCollection <ICommandRegistration> commandRegistrations)
        {
            if (actor == null)
            {
                throw new ArgumentNullException(nameof(actor));
            }

            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            var rootCommand = GetCommandRegistration(actor, args[0], commandRegistrations.Where(d => d.ParentId == null));

            if (rootCommand == null)
            {
                var exceptionContext = new CommandContext(null, actor, args.First(), prefix, args.Skip(1).ToList(), m_LifetimeScope.BeginLifetimeScopeEx());
                var localizer        = m_LifetimeScope.Resolve <IOpenModStringLocalizer>();
                exceptionContext.Exception = new CommandNotFoundException(localizer["commands:errors:not_found", new { CommandName = args[0], Args = args }]);
                //await actor.PrintMessageAsync(Color.Red, exceptionContext.Exception.Message);
                return(exceptionContext);
            }

            var scope       = rootCommand.Component.LifetimeScope.BeginLifetimeScopeEx("AutofacWebRequest");
            var rootContext = new CommandContext(rootCommand, actor, args.First(), prefix, args.Skip(1).ToList(), scope);

            return(BuildContextTree(rootContext, commandRegistrations));
        }
Example #2
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>().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 lifetimeScope = m_LifetimeScope.BeginLifetimeScopeEx(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(_ => 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(_ => m_DataStoreFactory.CreateDataStore(new DataStoreCreationParameters
                        {
#pragma warning disable 618
                            ComponentId = pluginMetadata.Id,
#pragma warning restore 618
                            Prefix           = null,
                            Suffix           = "data",
                            WorkingDirectory = workingDirectory
                        }))
                        .As <IDataStore>()
                        .SingleInstance()
                        .OwnedByLifetimeScope();

                        var stringLocalizer = Directory.Exists(workingDirectory)
                            ? m_StringLocalizerFactory.Create("translations", workingDirectory)
                            : NullStringLocalizer.Instance;

                        containerBuilder.Register(_ => 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)ActivatorUtilitiesEx.CreateInstance(m_LifetimeScope, 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 pluginLoggerType = typeof(ILogger <>).MakeGenericType(pluginType);
                    var pluginLogger     = (ILogger)pluginInstance.LifetimeScope.Resolve(pluginLoggerType);

                    RegisterConfigChangeCallback(pluginInstance, pluginLogger);

                    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);
            }
        }